【多进程与多线程】

调度 : 在传统计算机操作系统中 cpu的调度的基本单位是进程,随着线程的引入,线程变成操作系统的最小调度单位

而进程是作为资源的拥有单位。

并行:由于线程的引入 原先一个进程只能有一个并发 现在一个进程可以有多个线程并行执行,

     早起的httpserver 都是通过线程来解决服务器的并发 比起之前用fork子进程来处理并发效率有很大的提升。

     这一切得益于线程可以用进程更低的代价实现并发。

共享 :一般linux线程会让线程继承或共享如下资源

。进程的共有数据内存

。 进程所打开的文件描述符

。 信号的处理器

。 进程用户的ID和进程组ID

隔离:

。线程ID ,在linux中 线程和进程共享ID空间

    。寄存器的值

    。线程的栈

    。 优先级  linux的系统设计使得线程和进程除了在某些资源的共享和隔离有差异外,几乎是一视同仁的,他们可以有不同观点priority

我们在选择多进程还是多线程的时候需要根据业务场景使用。他们特性就是共享和隔离的区别。

【Linux的进程】

Linux在linus设计的时候的定位就是一个多任务的操作系统,从linux出的第一个版本的时候 就有了 进程的概念,

  线程的产生是为了解决并发问题,线程的定位也就是更小更轻的进程

  一些问题:

为什么不能一味的开线程解决并发问题?

    #线程的上下文切换所带来的消耗,开的线程越多,在上下文切换过程中消耗就越大,核心就是内存根不上cpu的速度。    

  上下文切换: 在cpu还是单核的时候,计算机操作系统就已经实现了多任务系统,但是你要知道 单核的cpu在同一时间段内

       只能执行某一个进程的某一个指令,为了达到多任务的执行效果,linux把cpu的时间切成大小不到等的时间

        片,通过内核调度算法,让进程一个个上去跑,由于切换时间片的时间非常短,在我们人类看来 计算机在同时执行多个程序。

             那么这个是如果实现的呢,如果程序到了时间片结束之后还没有完成它的工作,那么操作系统会把这个程序,以及其依赖的数据

       都保存在内存里,然后回到进程的队列里。保存现场是需要代价的,这将极大的影响cpu的分支预测,影响系统性能,

        所以频繁的上下文切换,是我们及其避免的。

【协程】

  协程就是用户自己在进程中控制多任务的栈,尽可能的不让进程由于外部中断或者IO的等待丧失CPU调度的时间片,从而在进程内部实现并发。

【内存与守护进程】    

程序运行时的内存,也就是我们在用户状态能看到的内存地址,都不是物理内存的地址,现代操作系统都会在物理内存上做一层,内存映射,每个

进程内的内存空间都是独立的

守护进程的特点:

  1 后台运行,也不占用conscle的前面 也就是bash里运行程序后面加个&

  2 成为  process group leader 守护进程的父进程是init的那个进程

  3 成为 session leader 一个ssh登陆会启动一个bash bash会fork很多子进程,这些进程轮流接受tty输出,这都是一个session session leader就是一队进程的父进程

  4 fork 一次到两次 因为linux父进程只对子进程负责,fork两次可以保证不影响正在执行的程序,直接交给init

  5 chdir到/ 防止占用别的路径的 working dir的id 导致block不能

  6 需要重置umask 方式后续子进程继承非默认umask造成不可控问题

  7 处理标准输入输出 错误输出(0,1,2) 重定向stdout stderr stdin 防止tty中断后的broken pipe信号

8 日志 输入重定向后,需要有办法反映内部情况

--关于僵尸进程--父进程派生出子进程 如果子进程挂了 但是一般进程 父进程会拿着子进程的pid 调用wait,如果父进程对子进程没有处理,这个这个时候就会变成僵尸进程

如果父进程也挂了init会回收僵尸进程 而僵尸进程存的就是僵尸进程退出的退出码。

【用python写一个守护进程】

#!/usr/bin/env python
#coding=utf-8
import os,sys
import time ''' 使用python写个守护进程
''' def daemonzie(stdin='/dev/null',stdout='/dev/null',stderr='/dev/null'):
try:
pid = os.fork()
if pid >0:
sys.exit(0) except OSError ,e:
sys.stderr.write("fork #2 failed (%d) %s\n "%(e.errno,e.strerror))
sys.exit(1) os.chdir('/')# chdir到/ 防止占用别的路径的 working dir的id 导致block不能
os.umask(0)#需要重置umask 方式后续子进程继承非默认umask造成不可控问题
os.setsid()#成为  process group leader 守护进程的父进程是init的那个进程 try:
pid = os.fork()
if pid >0:
sys.exit(0) except OSError,e:
sys.stderr.write("fork #2 failed (%d) %s\n " % (e.errno, e.strerror))
sys.exit(1) for i in sys.stdout,sys.stderr:i.flush()
si = open(stdin,'r+')
so = open(stdout,'a+')
se = open(stderr,'a+',0)
os.dup2(si.fileno(),sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdin.fileno())
os.dup2(se.fileno(), sys.stdin.fileno()) def main():
import time
sys.stdout.write('Daemon started with pid %s\n'%os.getpid())
sys.stdout.write('Daemon stdout output\n')
sys.stderr.write('Daemon stderr output\n')
c = 0
while 1:
sys.stdout.write('%d:%s\n'%(c,time.ctime()))
sys.stdout.flush()
c + c+1
time.sleep(1) if __name__ == '__main__':
daemonzie('/dev/null','/tmp/daemon_stdout.log','/tmp/daemon_error.log')
main()

 说白了 我们写一个 while 1 :print 'xxxx' 这种其实就是守护进程的基础 我们需要对一些东西进行处理后 才能形成一个正常的守护进程

【多线程实例】

1>

#!/usr/bin/env python
#coding:utf-8 import thread def f(name):
#定义线程函数
print 'this is '+name if __name__ == '__maim__':
thread.start_new_thread(f,("thread1",))
while 1:
pass

  

2>

#/usr/bin/env python
#coding:utf-8 import threading class Th(threading.Thread):
def __init__(self,name):
threading.Thread.__init__(self)
self.t_name = name
def run(self):
print "this is " + self.t_name if __name__ == '__main__':
thread1= Th("Thread1")
thread1.start()

  

threading.Thread 类的可继承函数
getName() 获得线程对象名称
setName() 设置线程对象名称 join() 等待调用的线程件数后再运行的命令 setDaemin(bool)阻塞模式
  True 父线程不等待子线程的结束
  False 等待默认为等待
isDaemon() 判断子线程是否和父线程一起结束 即setDaemon() 设置的值
isAlive()判断线程是否在运行
import threading
import time class my_therad(threading.Thread):
def __init__(self,thread_name):
threading.Thread.__init__(self)
self.setName=(thread_name) def run(self):
print 'this is thread'+ self.getName()
for i in range(5):
time.sleep(1)
print(str(i))
print self.getName()+'is over' if __name__ == '__main__':
thread1 = my_therad('T1')
thread1.start()
#thread1.join()
print 'main thread is over'

 这里如果加了join()

this is threadThread-1
0
1
2
3
4
Thread-1is over
main thread is over

 如果没加

this is threadThread-1
main thread is over
0
1
2
3
4
Thread-1is over

 加了join 主线程会等待子线程结束返回之后才会执行

-------------------------------------------------------------------

import threading
import time class my_therad(threading.Thread):
def __init__(self,thread_name):
threading.Thread.__init__(self)
self.setName=(thread_name) def run(self):
print 'this is thread'+ self.getName()
for i in range(5):
time.sleep(1)
print(str(i))
print self.getName()+'is over' if __name__ == '__main__':
thread1 = my_therad('T1')
thread1.setDaemon(True)
thread1.start()
#thread1.setDaemon(True)
#thread1.join()
print 'main thread is over'

  如果setDaemon 在start之前那么 主线程不会等待子线程,直接结束了

输出:

起多个子线程

if __name__ == '__main__':
for i in range(3):
t = my_therad(str(i))
t.start()
print 'main thread is over'

  【线程锁】

import  threading

import time

class Th(threading.Thread):
def __init__(self,thread_name):
threading.Thread.__init__(self)
self.setName(thread_name) def run(self):
threadLock.acquire()
print "this is thread "+self.getName()
for i in range(3):
time.sleep(1)
print str(i)
print self.getName()+' is over'
threadLock.release() if __name__ == '__main__':
threadLock = threading.Lock()
thread1 = Th('Thread_1')
thread2 = Th('Thread_2')
thread1.start()
thread2.start()

  如果加上锁输出就是这样

this is thread Thread_1
0
1
2
Thread_1 is over
this is thread Thread_2
0
1
2
Thread_2 is over

  

如果不加

this is thread Thread_1
this is thread Thread_2
0
0
1
1
2
Thread_2 is over
2
Thread_1 is over

  在thread中 优先会让之前拿到锁的人去拿锁 这样可以保证cpu分支预测的成功率

=======================================================================================================

#!/usr/bin/env python
#coding:utf-8
#####################
# time:2017-08-11 #
#####################
'''
this class is Daemon class ''' import os,sys,time,atexit from signal import SIGTERM class Daemon():
def __init__(self,pidfile = 'nbmon.pid',stdin='/dev/null',stdout='nbmon.log',stderr ='nbmon.log'):
self.stdin = stdin
self.stdout =stdout
self.stderr = stderr
self.pidfile = pidfile def daeminize(self):
try:
pid = os.fork()
if pid > 0:
sys.exit(0)
except OSError ,e:
sys.stderr.write("fork #1 failed:%d(%s)"(e.errno,e.strerror))
sys.exit(1) os.chdir('/')
os.setsid()
os.umask(0) try:
pid = os.fork()
if pid > 0:
sys.exit(0)
except OSError ,e:
sys.stderr.write("fork #2 failed:%d(%s)"(e.errno,e.strerror))
sys.exit(1) sys.stdout.flush()
sys.stderr.flush()
si= file(self.stdin,'r')
so= file(self.stdout,'a+')
se = file(self.stderr,'a+',0)
os.dup2(si.fileno(),sys.stdin.fileno())
os.dup2(si.fileno(),sys.stdout.fileno())
os.dup2(si.fileno(),sys.stderr.fileno())
atexit.regoster(self.delpid)
pid = str(os.getpid())
file(self.pidfile,'w+'.write("%s\n"%pid)) def delpid(self):
os.remove(self.pidfile) def start(self):
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError,e:
pid = None if pid :
message = "pidfile %s alreadly exit,Daemon is running\n"
sys.stderr.write(message % self.pidfile)
sys.exit(1) self.daemonize()
self.run() def stop(self):
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close except IOError:
pid = None if not pid:
message = "pidfile %s does not exitst,Daemon is running\n"
sys.stderr.write(message % self.pidfile)
return
try:
while 1:
os.kill(pid,STGTERM)
time.sleep(0.1)
except OSError,err:
err = str(err)
if err.find("No such process") > 0 :
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
print srt(err)
sys.exit(1)
def restart(self):
self.stop()
self.start()
def run(self):
pass
#!/usr/bin/env  python
#coding:utf-8 from daemon import Daemon
import socket
import time html= """HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\nConnection: close\r\nContent-Length: """
html404 = """HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\nContent-Length: 13\r\n\r\n<h1>404 </h1>""" class agentD(Daemon):
def run(self):
listen_fd = socket.socket(socket.AF_INET,socket.SOCK_STREAM, 0)
listen_fd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_fd.bind(("0.0.0.0",9085))
listen_fd.listen(10)
while True:
conn,addr = listen_fd.accept()
print "coming",conn,addr
read_data = conn.recv(10000)
try:
pic_name = read_data.split(" ")[1][1:] print pic_name,'*********' with file(pic_name) as f:
pic_content = f.read()
lengths = len(pic_content)
print lengths,"####"
html_resp = html
html_resp += "%d\r\n\r\n" % (lengths)
print html_resp
html_resp += pic_content
except:
print "404 occur"
html_resp = html404
while len(html_resp)>0:
sent_cnt = conn.send(html_resp)
print "sent:",sent_cnt
html_resp = html_resp[sent_cnt:] conn.close() if __name__ == '__main__':
agentd = agentD(pidfile = 'agent.pid',stdout='agent.log',stderr ='agent.log')
agentd.run()

  


python-高级编程-03的更多相关文章

  1. python高级编程技巧

    由python高级编程处学习 http://blog.sina.com.cn/s/blog_a89e19440101fb28.html Python列表解析语法[]和生成 器()语法类似 [expr  ...

  2. python高级编程:有用的设计模式3

    # -*- coding: utf-8 -*-__author__ = 'Administrator'#python高级编程:有用的设计模式#访问者:有助于将算法从数据结构中分离出来"&qu ...

  3. python高级编程:有用的设计模式2

    # -*- coding: utf-8 -*- __author__ = 'Administrator' #python高级编程:有用的设计模式 #代理 """ 代理对一 ...

  4. python高级编程:有用的设计模式1

    # -*- coding: utf-8 -*-__author__ = 'Administrator'#python高级编程:有用的设计模式#设计械是可复用的,某种程序上它对软件设计中觉问题提供的语言 ...

  5. python高级编程之选择好名称:完

    由于时间关系,python高级编程不在放在这边进行学习了,如果需要的朋友可以看下面的网盘进行下载 # # -*- coding: utf-8 -*- # # python:2.x # __author ...

  6. python高级编程读书笔记(一)

    python高级编程读书笔记(一) python 高级编程读书笔记,记录一下基础和高级用法 python2和python3兼容处理 使用sys模块使程序python2和python3兼容 import ...

  7. python高级编程之列表推导式

    1. 一个简单的例子 在Python中,如果我们想修改列表中所有元素的值,可以使用 for 循环语句来实现. 例如,将一个列表中的每个元素都替换为它的平方: >>> L = [1, ...

  8. Python高级编程之生成器(Generator)与coroutine(二):coroutine介绍

    原创作品,转载请注明出处:点我 上一篇文章Python高级编程之生成器(Generator)与coroutine(一):Generator中,我们介绍了什么是Generator,以及写了几个使用Gen ...

  9. Python高级编程-Python一切皆对象

    Python高级编程-Python一切皆对象 Python3高级核心技术97讲 笔记 1. Python一切皆对象 1.1 函数和类也是对象,属于Python的一等公民 ""&qu ...

  10. 第三章:Python高级编程-深入类和对象

    第三章:Python高级编程-深入类和对象 Python3高级核心技术97讲 笔记 3.1 鸭子类型和多态 """ 当看到一直鸟走起来像鸭子.游泳起来像鸭子.叫起来像鸭子 ...

随机推荐

  1. Android 贝塞尔曲线的浅析

    博客也开了挺长时间了,一直都没有来写博客,主要原因是自己懒---此篇博客算是给2017年一个好的开始,同时也给2016年画上一个句点,不留遗憾. 那就让我们正式进入今天的主题:贝塞尔曲线. 首先,让我 ...

  2. SCCM Collection 集合获取计算机最后启动时间

    获取计算机客户端最后一次启动时间,我们可以通过多种来源获取,如活动目录组 ,而不仅仅是SCCM 收集,希望对您有所帮助,下面分享PowerShell 脚本 # 1 $CollectionName = ...

  3. js修改文档的样式

    <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Java ...

  4. POJ 1651 Multiplication Puzzle (区间DP,经典)

    题意: 给出一个序列,共n个正整数,要求将区间[2,n-1]全部删去,只剩下a[1]和a[n],也就是一共需要删除n-2个数字,但是每次只能删除一个数字,且会获得该数字与其旁边两个数字的积的分数,问最 ...

  5. FlowVisor相关

    1. FlowVisor工作原理(转) 作为一个网络虚拟化平台,FlowVisor部署在标准OpenFlow控制器和OpenFlow交换机之间,成为二者的透明代理.FlowVisor能够与多个控制器连 ...

  6. ubuntu下安装eclipse<转>

    转载自http://my.oschina.net/u/1407116/blog/227084      http://my.oschina.net/u/1407116/blog/227087 一 JD ...

  7. python 与 json

    +-------------------+---------------+    | Python            | JSON          |    +================= ...

  8. 读书笔记-《深入理解Java虚拟机:JVM高级特性与最佳实践》

    目录 概述 第一章: 走进Java 第二章: Java内存区域与内存溢出异常 第三章: 垃圾收集器与内存分配策略 第四章: 虚拟机性能监控与故障处理 第五章: 调优案例分析与实战 第六章: 类文件结构 ...

  9. axios的post请求方法---以Vue示例

    Axios向后端提交数据的参数格式是json,而并非用的是form传参,post表单请求提交时,使用的Content-Type是application/x-www-form-urlencoded,而使 ...

  10. Dojo操作dom元素的样式

    1.使用dom-style的set方法,可以直接设置dom元素的样式属性,这和使用dom元素的style属性效果一样. 2.使用dom-class的replace方法可以替换某个dom元素的样式,ad ...