python--进程,线程,协程
进程
进程的相关概念:http://www.cnblogs.com/chaguang/p/7818440.html
在python中创建进程用到了multiprocessing中的Process类
创建进程,使用Process中的def __init__(self, group=None, target=None, name=None, args=(), kwargs={})
参数:
- target:表示调用对象
- args:表示调用对象的位置参数元组
- kwargs:表示调用对象的字典
- name:为别名
- group:实质上不使用
方法:
- is_alive():如果进程是运行的,返回True
- join([timeout]):主进程是否等待子进程结束,没有传递超时时间timeout则为等待子进程结束,如果设置了timeout,表示最多等待timeout时间
- run():运行target参数指定的函数
- start():启动进程,并调用子进程中的run方法
- terminate():终止进程,不进行任何清理操作,如果该进程有子进程,那么就会变成僵尸进程
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from multiprocessing import Process
2 g_i=1
3 def f1(i):
4 global g_i
5 g_i+=1
6 print(i,g_i)
7 #进程的相关信息必须放在if __name__=="__main__":中,否则会报错
8 if __name__=="__main__":
9 for i in range(5):
10 #args后的括号内必须加,
11 p=Process(target=f1,args=(i,))
12 #启动进程
13 p.start()
注意事项
- 在windows中Process()必须放到# if __name__ == '__main__':下
- 参数args的括号中必须带,,否则会报错,例如args=(i,)
- 进程的数据默认不共享的,各自有一份,所以在创建多进程的时候,系统开销比较大
进程间的数据共享
- Array
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from multiprocessing import Process,Array 2 import time 3 #Array相当于c中的数组,规定类型都需要一样 4 g_data=Array("i",[1,2,3,4,5,6]) 5 # 类型: 6 # 'c': ctypes.c_char, 'u': ctypes.c_wchar, 7 # 'b': ctypes.c_byte, 'B': ctypes.c_ubyte, 8 # 'h': ctypes.c_short, 'H': ctypes.c_ushort, 9 # 'i': ctypes.c_int, 'I': ctypes.c_uint, 10 # 'l': ctypes.c_long, 'L': ctypes.c_ulong, 11 # 'f': ctypes.c_float, 'd': ctypes.c_double 12 def sum(i): 13 g_data[i]+=i 14 15 if __name__=="__main__" : 16 for i in range(6): 17 pro=Process(target=sum,args=(i,)) 18 pro.start() 19 pro.join()
- manage.dict()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from multiprocessing import Process,Manager 2 3 4 def sum(dic,i): 5 if i <5: 6 dic[i]=i 7 else: 8 dic[i]="sdafsd" 9 print(dic[i],dic.values()) 10 11 if __name__=="__main__" : 12 #创建一个Manager()对象 13 ma = Manager() 14 #创建一个进程间能够共享数据的“字典”,不需要类型统一 15 dic = ma.dict() 16 for i in range(6): 17 pro=Process(target=sum,args=(dic,i,)) 18 pro.start() 19 pro.join() 20 21 22 23 24 25 26 #
进程池
在python中,multiprocessing模块里提供了Pool的使用
进程池的一些方法:
- apply:同步执行,内部有调用了join,一个一个执行,主进程等子进程结束,它才结束
- apply_async:异步执行,并且可以设置回调函数,内部没有调用join,主进程不等子进程结束,可以调用pool对象.join()让主进程等待子进程,但是有一个限制,需要再其前面加p.close()(等任务执行完之后再终止)或者p.terminate()(立即终止所有的任务),调用函数的返回值可以传递给回调函数的参数
- close:关闭进程池
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from multiprocessing import process,Pool 2 import time 3 def f1(): 4 print("f1") 5 time.sleep(2) 6 return 0 7 #f2的参数a是调用函数f1的返回值 8 def f2(a): 9 print("f2:this is a callback~",a) 10 return 1 11 if __name__=="__main__": 12 #创建一个有5个进程数的进程池 13 pool=Pool(5) 14 for i in range(5): 15 #使用进程池 16 # pool.apply(func=f1) 17 pool.apply_async(func=f1,callback=f2) 18 print("end") 19 pool.close() 20 pool.join()
线程
线程的相关概念:http://www.cnblogs.com/chaguang/p/7818456.html
全局解释器锁GIL
threading模块
threading模块中的对象
Thread | 表示一个执行线程的对象 |
Lock | 锁原语对象 |
RLock | 可重入锁对象,使单一线程可以获得已持有的锁 |
Condition | 条件变量对象,使得一个线程等待另一个线程满足特定的“条件” |
Event | 条件变量的通用版本,任意数量的线程等待某个事件发生,在该事件发生后所有的线程都将被激活 |
Semaphore | 为线程间共享的有限资源提供一个“计数器”,如果没有可用资源时,会被阻塞 |
BoundedSemaphore | 与Semaphore相似,不过它不允许超过初始值 |
Timer | 与Thread相似,不过它要在运行前等待一段时间 |
Barrier | 创建一个“障碍”,必须达到指定数量的线程后才可以继续 |
threading模块中的对象Lock,RLock,Condition,Semaphore和BoundeSemaphore都包含上下文管理器,即可以使用with语句
Thread类
Thread对象的数据属性:
- name:线程名
- ident:线程的标识符
- daemon:布尔标志。表示该线程是否为守护线程,即进程退出的时候不需要等待这个线程执行完成
Thread对象方法:
start() 开始执行该线程 run() 定义线程功能的方法(通常在子类中被重写) join([timeout]) 直至启动的线程终止之前一直挂起,除非给出timeout,否则会一直阻塞 getName() 返回线程名 setName(name) 设置线程名
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import threading 2 3 class myThread(threading.Thread): 4 def __init__(self,func,args,name=''): 5 threading.Thread.__init__(self) 6 self.name=name 7 self.func=func 8 self.args=args 9 10 def run(self): 11 self.func(*self.args) 12 def fun(*args): 13 print(args) 14 15 if __name__=="__main__": 16 obj=myThread(fun,("诸葛",)) 17 obj.start()
线程锁Lock和RLock
为了解决线程同步的问题,python在threading模块中提供了Lock和RLock,互斥锁 同时只允许一个线程更改数据,有两种状态:锁定和未锁定。而且它也支持两个函数:获得锁和释放锁
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import threading 2 3 g_num=1 4 g_lock = threading.RLock() 5 6 class myThread(threading.Thread): 7 def __init__(self,func,args,name=''): 8 threading.Thread.__init__(self) 9 self.name=name 10 self.func=func 11 self.args=args 12 13 def run(self): 14 self.func(*self.args) 15 def fun(*args): 16 print(args) 17 global g_num 18 #获得锁 19 # g_lock.acquire() 20 # g_num+=100 21 # print(g_num) 22 # g_lock.release() 23 #上面的情况也可以写成with语句中,上下文管理器负责在进入之前调用acquire,执行完之后调用release 24 with g_lock: 25 g_num+=100 26 print(g_num) 27 28 if __name__=="__main__": 29 for i in range(5): 30 obj=myThread(fun,("诸葛",)) 31 obj.start()
信号量(Semaphore)
Semaphore也是为了解决线程同步的问题,与互斥锁不同的是,Semaphore同时允许一定数量的线程更改数据,它是一个计数器,当资源消耗的时候递减,当资源释放的时候递增
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import threading 2 import time 3 g_num=1 4 #设置资源数为5,即可以同时被5个线程执行临界区的内容 5 g_lock = threading.Semaphore(5) 6 7 class myThread(threading.Thread): 8 def __init__(self,func,args,name=''): 9 threading.Thread.__init__(self) 10 self.name=name 11 self.func=func 12 self.args=args 13 14 def run(self): 15 self.func(*self.args) 16 def fun(*args): 17 print("acquire") 18 global g_num 19 # 获得锁 20 g_lock.acquire() 21 print(args[1]) 22 time.sleep(2) 23 print("release") 24 #释放锁 25 g_lock.release() 26 27 28 if __name__=="__main__": 29 for i in range(5): 30 obj=myThread(fun,("诸葛",1)) 31 obj.start()
事件(event)
python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from threading import Thread,Event 2 import time 3 #创建一个事件对象 4 event_obj=Event() 5 6 def f1(): 7 print("wait........") 8 #等待event_obj.set()方法 9 event_obj.wait() 10 print("start.........") 11 12 if __name__=="__main__": 13 for i in range(5): 14 thread=Thread(target=f1) 15 thread.start() 16 17 print("sleeping....") 18 19 time.sleep(3) 20 event_obj.set()
条件(Condition)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import threading 2 #该函数用来判断条件,返回True的话,con.wait_for()向下执行 3 def condition_func(): 4 ... 5 return True 6 7 def run(n): 8 #获得锁 9 con.acquire() 10 #当condition_func返回True时候才向下执行,wait_for的参数需要是可以调用的对象 11 con.wait_for(condition_func) 12 print(n) 13 # 释放锁 14 con.release() 15 16 if __name__ == '__main__': 17 #创建一个condition对象 18 con = threading.Condition() 19 for i in range(10): 20 t = threading.Thread(target=run, args=(i,)) 21 t.start()
Timer
定时器,指定n秒后才开始执行操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from threading import Timer 2 def f1(): 3 print("start run....") 4 5 t=Timer(3,f1) 6 t.start()
线程池
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #线程池 2 import threading 3 import contextlib 4 import queue 5 6 #用来当终止符 7 stopTask=object() 8 9 class ThreadPool(object): 10 def __init__(self,maxNum,maxTaskNum=None): 11 if maxTaskNum: 12 self.taskQueue=queue.Queue(maxTaskNum) 13 else: 14 self.taskQueue=queue.Queue() 15 #最大线程数 16 self.maxNum=maxNum 17 #空闲线程 18 self.freeThread=[] 19 #正在运行的线程 20 self.runningThread=[] 21 #判断是否要终止线程池,清空所有的任务 22 self.terminate=False 23 def Run(self,func,args,callback=None): 24 #如果没有空闲的线程 25 if len(self.freeThread)==0 or len(self.runningThread)<self.maxNum: 26 #创建一个线程 27 self.CreateThread() 28 lis=(func,args,callback,) 29 #将任务放在任务列表中 30 self.taskQueue.put(lis) 31 32 def CreateThread(self): 33 obj=threading.Thread(target=self.call) 34 #开始执行线程,让线程去处理任务 35 obj.start() 36 37 def call(self): 38 #获取当前线程 39 currentThread=threading.current_thread() 40 #将线程添加到正在执行线程的列表中 41 self.runningThread.append(currentThread) 42 43 #开始取任务,然后处理任务 44 task=self.taskQueue.get() 45 while task!=stopTask: 46 func,args,callback=task 47 #执行任务中的处理函数,并将其参数传递给func函数 48 ret=func(*args) 49 if callback != None: 50 #如果回调函数不为空,则将调用结果的返回值传给回调函数 51 callback(ret) 52 #************************************************# 53 # #处理完任务,重新获取任务 54 # self.freeThread.append(currentThread) 55 # #如果终止符标记符为True,那么就向任务队列中投放终止符 56 # if self.terminate: 57 # #self.taskQueue.put(stopTask) 58 # task=stopTask 59 # else: 60 # task=self.taskQueue.get() 61 # self.freeThread.remove(currentThread) 62 #***********************************************# 63 #上面的*号括着的内容等价于下面with里面的内容,主要是因为被@contextlib.contextmanager 64 #修饰的worker_state函数 65 with self.worker_state(self.freeThread,currentThread): 66 if self.terminate: 67 task = stopTask 68 else: 69 task = self.taskQueue.get() 70 #收到了终止符号,终止线程 71 else: 72 self.runningThread.remove(currentThread) 73 74 def Close(self): 75 #关闭线程池 76 threadNum=len(self.runningThread) 77 while threadNum: 78 self.taskQueue.put(stopTask) 79 threadNum-=1 80 81 def Terminate(self): 82 #立即关闭线程池,清空所有的任务 83 self.terminate=True 84 while self.runningThread: 85 self.taskQueue.put(stopTask) 86 #清空任务对列 87 self.taskQueue.queue.clear() 88 #利用上下文管理 89 @contextlib.contextmanager 90 def worker_state(self, state_list, worker_thread): 91 state_list.append(worker_thread) 92 try: 93 yield 94 finally: 95 state_list.remove(worker_thread) 96 97 98 99 def ca(re): 100 print("callback,f1 return value %s"%re) 101 102 def f1(*args): 103 print(args) 104 return 0 105 106 obj=ThreadPool(3) 107 108 for i in range(5): 109 obj.Run(f1,(11,22,33,),ca) 110 111 obj.Terminate()
协程
在协程中,控制可以从当前执行上下文跳转到程序的其它位置,并且可以在之后的任意时刻恢复当前执行上下文,控制从跳出点处继续执行。协程主要用在程序中有大量的IO操作的时候,这时候虽然可以用多线程的解决,但是这可能导致多个线程进行等待,这时就可以使用协程来解决,利用一个线程去等待多个IO操作。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from greenlet import greenlet 2 3 def test1(): 4 print("12") 5 gr2.switch() 6 print("34") 7 gr2.switch() 8 9 def test2(): 10 print("56") 11 gr1.switch() 12 print("78") 13 14 gr1 = greenlet(test1) 15 gr2 = greenlet(test2) 16 gr1.switch() 17 ######输出############ 18 12 19 56 20 34 21 78
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # from gevent import monkey; monkey.patch_socket() 2 import gevent 3 4 def f(n): 5 for i in range(n): 6 print(gevent.getcurrent(), i) 7 gevent.sleep() 8 9 # g1 = gevent.spawn(f, 5) 10 # g2 = gevent.spawn(f, 5) 11 # g3 = gevent.spawn(f, 5) 12 # g1.join() 13 # g2.join() 14 # g3.join() 15 #或者写成下面的形式 16 gevent.joinall([ 17 gevent.spawn(f,5), 18 gevent.spawn(f,5), 19 gevent.spawn(f,5), 20 ])