python多线程学习笔记
一.多线程相关python包/模块
1.thread
该模块有问题,使用不便,在python3中被保留,并且改成了_thread
2.threading
python3中通用的多线程包
二.什么是多线程
案例1:
无多线程程序代码
1 import time 2 3 def loop1(): 4 print('loop1 begining:',time.ctime()) 5 time.sleep(4) 6 print('loop1 ending:',time.ctime()) 7 8 def loop2(): 9 print('loop2 begining:',time.ctime()) 10 time.sleep(2) 11 print('loop2 ending:',time.ctime()) 12 13 def main(): 14 print('main beginging',time.ctime()) 15 loop1() 16 loop2() 17 print('main ending',time.ctime()) 18 19 if __name__ == '__main__': 20 main()
main beginging Wed Aug 22 21:33:34 2018 loop1 begining: Wed Aug 22 21:33:34 2018 loop1 ending: Wed Aug 22 21:33:38 2018 loop2 begining: Wed Aug 22 21:33:38 2018 loop2 ending: Wed Aug 22 21:33:40 2018 main ending Wed Aug 22 21:33:40 2018
案例2:
含有多线程程序代码1
1 import time 2 import _thread as thread 3 4 def loop1(): 5 print('loop1 begining:',time.ctime()) 6 time.sleep(4) 7 print('loop1 ending:',time.ctime()) 8 9 def loop2(): 10 print('loop2 begining:',time.ctime()) 11 time.sleep(2) 12 print('loop2 ending:',time.ctime()) 13 14 def main(): 15 print('main beginging:',time.ctime()) 16 thread.start_new_thread(loop1,()) 17 thread.start_new_thread(loop2,()) 18 print('main ending:',time.ctime()) 19 20 if __name__ == '__main__': 21 main()
main beginging: Wed Aug 22 21:35:07 2018
main ending: Wed Aug 22 21:35:07 2018
启动多线程函数:start_new_thead
参数两个,一个是需要运行的函数名,第二是函数的参数作为元祖使用,为空则使用空元祖
注意:如果函数只有一个参数,需要参数后由一个逗号
案例中,main函数执行完,程序立刻退出.loop1,loop2并没有执行完
main函数相当于包工头
loop1,loop2相当于工人
main函数(包工头)分配loop1,loop2(工人)任务之后,立刻报告给boss,没有等loop1,loop2完成各自的任务
案例3:
含有多线程程序代码2-改进版
1 import time 2 import _thread as thread 3 4 def loop1(): 5 print('loop1 begining:',time.ctime()) 6 time.sleep(4) 7 print('loop1 ending:',time.ctime()) 8 9 def loop2(): 10 print('loop2 begining:',time.ctime()) 11 time.sleep(2) 12 print('loop2 ending:',time.ctime()) 13 14 def main(): 15 print('main beginging:',time.ctime()) 16 thread.start_new_thread(loop1,()) 17 thread.start_new_thread(loop2,()) 18 print('main ending:',time.ctime()) 19 20 if __name__ == '__main__': 21 main() 22 while True: 23 time.sleep(1)
main beginging: Wed Aug 22 21:45:10 2018 main ending: Wed Aug 22 21:45:10 2018 loop1 begining: Wed Aug 22 21:45:10 2018 loop2 begining: Wed Aug 22 21:45:10 2018 loop2 ending: Wed Aug 22 21:45:12 2018 loop1 ending: Wed Aug 22 21:45:14 2018
在改进案例中:
增加while True: // time.sleep()
while True:无限循环
这样就避免了程序在main函数执行完后立刻退出,使得loop1,loop2得以执行
案例4:
含有多线程程序代码3-带参数
1 from time import ctime,sleep 2 import _thread as thread 3 4 def loop1(x): 5 print('loop1 begining:',ctime()) 6 sleep(4) 7 print('LOOP1:I am {0}'.format(x)) 8 print('loop1 ending: ' ,ctime()) 9 10 def loop2(x,y): 11 print('loop2 begining:',ctime()) 12 sleep(2) 13 print('LOOP2:I am {0}\nLOOP2:I am {1}'.format(x,y)) 14 print('loop2 ending: ' ,ctime()) 15 16 def main(): 17 print('main begining:',ctime()) 18 thread.start_new_thread(loop1,('Jone',)) 19 thread.start_new_thread(loop2,('Tom','king')) 20 print('main ending: ',ctime()) 21 22 if __name__ == '__main__': 23 main() 24 while True: 25 sleep(1)
三.threading模块的使用
案例1:
1 import time 2 import threading 3 4 def loop1(x): 5 print('loop1 start:',time.ctime()) 6 print('LOOP1:I am ',x) 7 time.sleep(4) 8 print('loop1 end:',time.ctime()) 9 10 def loop2(x,y): 11 print('loop2 start:',time.ctime()) 12 print('LOOP2:I am',x) 13 print('LOOP2:I am',y) 14 time.sleep(2) 15 print('loop2 end:',time.ctime()) 16 17 def main(): 18 print('main start:',time.ctime()) 19 t1 = threading.Thread(target = loop1,args = ('JONE',)) 20 t2 = threading.Thread(target = loop2,args = ('KIMI','SUKI')) 21 t1.start() 22 t2.start() 23 print('main end:',time.ctime()) 24 if __name__ == '__main__': 25 main()
main start: Wed Aug 22 23:41:38 2018 loop1 start: Wed Aug 22 23:41:38 2018 LOOP1:I am JONE loop2 start: Wed Aug 22 23:41:38 2018 LOOP2:I am KIMI LOOP2:I am SUKI main end: Wed Aug 22 23:41:38 2018 loop2 end: Wed Aug 22 23:41:40 2018 loop1 end: Wed Aug 22 23:41:42 2018
案例2:
join案例
1 import time 2 import threading 3 4 def loop1(x): 5 print('loop1 start:',time.ctime()) 6 print('LOOP1:I am ',x) 7 time.sleep(4) 8 print('loop1 end:',time.ctime()) 9 10 def loop2(x,y): 11 print('loop2 start:',time.ctime()) 12 print('LOOP2:I am',x) 13 print('LOOP2:I am',y) 14 time.sleep(2) 15 print('loop2 end:',time.ctime()) 16 17 def main(): 18 print('main start:',time.ctime()) 19 t1 = threading.Thread(target = loop1,args = ('JONE',)) 20 t2 = threading.Thread(target = loop2,args = ('KIMI','SUKI')) 21 t1.start() 22 t2.start() 23 24 t1.join() 25 t2.join() 26 print('main end:',time.ctime()) 27 if __name__ == '__main__': 28 main()
main start: Wed Aug 22 23:44:50 2018 loop1 start: Wed Aug 22 23:44:50 2018 LOOP1:I am JONE loop2 start: Wed Aug 22 23:44:50 2018 LOOP2:I am KIMI LOOP2:I am SUKI loop2 end: Wed Aug 22 23:44:52 2018 loop1 end: Wed Aug 22 23:44:54 2018 main end: Wed Aug 22 23:44:54 2018
t.start():开始启动多线程
t.join():等待多线性执行完成
threading.Thread(target = function,args = ())
可以发现,与_thread相比,没有while True 也能正常的执行
threading更为方便
四.守护线程
案例1:
无守护线程函数
1 import threading 2 import time 3 4 def fun(): 5 print('fun START') 6 time.sleep(2) 7 print('fun END') 8 9 t = threading.Thread(target = fun,args = ()) 10 t.start() 11 time.sleep(1) 12 print('main END')
fun START
main END
fun END
案例2:
存在守护线程函数
1 import threading 2 import time 3 4 def fun(): 5 print('fun START') 6 time.sleep(2) 7 print('fun END') 8 9 t = threading.Thread(target = fun,args = ()) 10 t.setDaemon(True) 11 t.start() 12 time.sleep(1) 13 print('main END')
fun START
main END
守护线程:
t.setDaemon(True)
或者
t.daemon = True
守护线程必须在start之前设置
在程序中把子线程设置成守护线程,那么在主线程结束的时候,该子线程也会跟着结束
通常,守护线程不可以离开主线程运行
守护线程,能否成功执行与编程环境有关
五.常用线程属性
1.threading.currentThread:返回当前线程变量
2.threadng.enumerate:返回一个包含正在运行的线程列表
3.threading.activeCount:返回正在运行线程数量,效果与len(threading.enumerate)相同
4.thr.setName:设置线程名字
5.thr.getName:获得线程名字
案例1:
1 import time 2 import threading 3 4 def loop1(): 5 print('loop1 start:',time.ctime()) 6 time.sleep(5) 7 print('loop1 end:',time.ctime()) 8 9 def loop2(): 10 print('loop2 start:',time.ctime()) 11 time.sleep(2) 12 print('loop2 start:',time.ctime()) 13 def loop3(): 14 print('loop3 start:',time.ctime()) 15 time.sleep(1) 16 print('loop3 end:',time.ctime()) 17 18 def main(): 19 print('MAIN START:',time.ctime()) 20 t1 = threading.Thread(target = loop1,args = ()) 21 t2 = threading.Thread(target = loop2,args = ()) 22 t3 = threading.Thread(target = loop3,args = ()) 23 t1.setName('Thr1') 24 t2.setName('Thr2') 25 t3.setName('Thr3') 26 t1.start() 27 t2.start() 28 t3.start() 29 time.sleep(3) 30 for i in threading.enumerate(): 31 print('正在运行的子线程有:',i.getName()) 32 print('正在运行的子线程数量是:',threading.activeCount()) 33 t1.join() 34 t2.join() 35 t3.join() 36 print('MAIN END:',time.ctime()) 37 38 if __name__ == '__main__': 39 main()
MAIN START: Fri Aug 24 23:27:08 2018 loop1 start: Fri Aug 24 23:27:08 2018 loop2 start: Fri Aug 24 23:27:08 2018 loop3 start: Fri Aug 24 23:27:08 2018 loop3 end: Fri Aug 24 23:27:09 2018 loop2 start: Fri Aug 24 23:27:10 2018 正在运行的子线程有: MainThread 正在运行的子线程有: Thr1 正在运行的子线程数量是: 2 loop1 end: Fri Aug 24 23:27:13 2018 MAIN END: Fri Aug 24 23:27:13 2018
六.线程继承
案例1:
1 import threading 2 import time 3 4 class Thread_My(threading.Thread): 5 def __init__(self,args): 6 self.args = args 7 def run(self): 8 time.sleep(2) 9 print('The arg is {0}'.format(self.args)) 10 print('The time is {0}'.format(time.ctime())) 11 12 for i in range(5): 13 t = Thread_My(i) 14 t.start() 15 t.join() 16 17 print('\nmian loop end',time.ctime())
Traceback (most recent call last): File "D:/pathon L/全栈/多线程/threading_inherit.py", line 15, in <module> t.start() File "C:\ProgramData\Anaconda3\lib\threading.py", line 839, in start raise RuntimeError("thread.__init__() not called") RuntimeError: thread.__init__() not called
报错,父类初始化__init__函数没有被调用,不能正常使用父类函数模块
案例2:
更改后
1 import threading 2 import time 3 4 class Thread_My(threading.Thread): 5 def __init__(self,args): 6 super(Thread_My,self).__init__() 7 self.args = args 8 def run(self): 9 time.sleep(2) 10 print('The arg is {0}'.format(self.args)) 11 print('The time is {0}'.format(time.ctime())) 12 13 for i in range(5): 14 t = Thread_My(i) 15 t.start() 16 t.join() 17 18 print('\nmian loop end',time.ctime())
The arg is 0 The time is Fri Aug 24 23:55:21 2018 The arg is 1 The time is Fri Aug 24 23:55:23 2018 The arg is 2 The time is Fri Aug 24 23:55:25 2018 The arg is 3 The time is Fri Aug 24 23:55:27 2018 The arg is 4 The time is Fri Aug 24 23:55:29 2018 mian loop end Fri Aug 24 23:55:29 2018
Thread_My继承threading.Thread的功能
run函数是原threading.Thread的内置函数
run函数代表真正执行的功能
将run函数改写成符合目的的函数
案例3:
继承——工业风
1 import threading 2 from time import sleep, ctime 3 4 5 6 class ThreadFunc: 7 8 def __init__(self, name): 9 self.name = name 10 11 def loop(self, nloop, nsec): 12 ''' 13 :param nloop: loop函数的名称 14 :param nsec: 系统休眠时间 15 :return: 16 ''' 17 print('Start loop ', nloop, 'at ', ctime()) 18 sleep(nsec) 19 print('Done loop ', nloop, ' at ', ctime()) 20 21 def main(): 22 print("Starting at: ", ctime()) 23 24 # ThreadFunc("loop").loop 跟一下两个式子相等: 25 # t = ThreadFunc("loop") 26 # t.loop 27 # 以下t1 和 t2的定义方式相等 28 t = ThreadFunc("loop") 29 t1 = threading.Thread( target = t.loop, args=("LOOP1", 4)) 30 # 下面这种写法更西方人,工业化一点 31 t2 = threading.Thread( target = ThreadFunc('loop').loop, args=("LOOP2", 2)) 32 33 # 常见错误写法 34 #t1 = threading.Thread(target=ThreadFunc('loop').loop(100,4)) 35 #t2 = threading.Thread(target=ThreadFunc('loop').loop(100,2)) 36 37 t1.start() 38 t2.start() 39 40 t1.join( ) 41 t2.join() 42 43 44 print("ALL done at: ", ctime()) 45 46 47 if __name__ == '__main__': 48 main()
七.共享变量问题
案例1:
1 import threading 2 3 sum = 0 4 sumd = 1000000 5 6 def my_Add(): 7 global sum,sumd 8 for i in range(sumd): 9 sum += 1 10 11 def my_Minu(): 12 global sum,sumd 13 for i in range(sumd): 14 sum -= 1 15 16 def main(): 17 print('main start:',sum) 18 t1 = threading.Thread(target = my_Add,args = ()) 19 t2 = threading.Thread(target = my_Minu,args = ()) 20 t1.start() 21 t2.start() 22 t1.join() 23 t2.join() 24 print('main end:',sum) 25 26 if __name__ == '__main__': 27 main()
main start: 0
main end: 462177
共享变量在多线程中被同时访问会出现混乱,如案例1
解决方法:锁,信号灯
八.锁(lock)
案例1:
1 import threading 2 3 sum = 0 4 sumd = 1000000 5 lock = threading.Lock() 6 7 def my_Add(): 8 global sum,sumd 9 for i in range(sumd): 10 lock.acquire() 11 sum += 1 12 lock.release() 13 14 def my_Minu(): 15 global sum,sumd 16 for i in range(sumd): 17 lock.acquire() 18 sum -= 1 19 lock.release() 20 21 def main(): 22 print('main start:',sum) 23 t1 = threading.Thread(target = my_Add,args = ()) 24 t2 = threading.Thread(target = my_Minu,args = ()) 25 t1.start() 26 t2.start() 27 t1.join() 28 t2.join() 29 print('main end:',sum) 30 31 if __name__ == '__main__': 32 main()
锁:标志一个线程在使用该资源
使用方法:
1.上锁:lock.acquire()
2.稳定使用共享资源
3.释放锁:lock.release()
九.线程安全问题
如果一个资源/变量在不加锁的情况下也不会引起任何问题,则为线程安全
线程安全变量类型:queue
线程不安全变量类型:list,set,dict...
十.生产消费者问题
案例1:
1 import threading 2 import queue 3 import time 4 5 class Producer(threading.Thread): 6 def run(self): 7 global queue 8 count = 0 9 while True: 10 if q.qsize() < 1000: 11 for i in range(100): 12 count += 1 13 msg = self.name + '生产产品' + str(count) 14 q.put(msg) 15 print(msg) 16 time.sleep(0.5) 17 18 class Customer(threading.Thread): 19 def run(self): 20 global queue 21 while True: 22 if q.qsize() > 100: 23 for i in range(3): 24 msg = self.name + '消费' + q.get() 25 print(msg) 26 time.sleep(1) 27 28 29 if __name__ == '__main__': 30 q = queue.Queue() 31 32 for i in range(500): 33 q.put('初始产品'+str(i)) 34 for i in range(2): 35 p = Producer() 36 p.start() 37 for i in range(5): 38 c = Customer() 39 c.start()
queue为用来存放变量的数据结构
特点:先进先出
可视为特殊的列表
q = queue.Queue()
q.qsize():返回q内容长度
q.put():在q中放入数据
q.get():在q中获得数据
十一.死锁问题
1 import threading 2 import time 3 4 l1 = threading.Lock() 5 l2 = threading.Lock() 6 7 def fun1(): 8 l1.acquire() 9 print('fun1 申请了 l1......') 10 time.sleep(2) 11 print('fun1 等待l2......') 12 l2.acquire() 13 print('fun1 申请了 l2......') 14 l1.release() 15 print('fun1 释放了 ll......') 16 l2.release() 17 print('fun1 释放了 l2......') 18 19 def fun2(): 20 l2.acquire() 21 print('fun2 申请了 l2......') 22 time.sleep(4) 23 print('fun2 等待l1......') 24 l1.acquire() 25 print('fun2 申请了 l1......') 26 l2.release() 27 print('fun2 释放了 l2......') 28 l1.release() 29 print('fun2 释放了 l1') 30 31 if __name__ == '__main__': 32 t1 = threading.Thread(target = fun1,args = ()) 33 t2 = threading.Thread(target = fun2,args = ()) 34 t1.start() 35 t2.start() 36 t1.join() 37 t2.join()
fun1 申请了 l1......
fun2 申请了 l2......
fun1 等待l2......
fun2 等待l1......
十二.锁的等待时间设置
案例1:
1 import time 2 import threading 3 4 lock_1 = threading.Lock() 5 lock_2 = threading.Lock() 6 7 def fun1(): 8 print('start fun1......') 9 lock_1.acquire() 10 print('fun1 申请了 lock_1...') 11 time.sleep(2) 12 print('fun1 等待 lock_2...') 13 st = lock_2.acquire(timeout = 10) 14 if st: 15 print('fun1 申请了 lock_2...') 16 lock_1.release() 17 print('fun1 释放了 lock_1...') 18 lock_2.release() 19 print('fun1 释放了 lock_2...') 20 else: 21 print('fun1 申请 lock_2 失败') 22 lock_1.release() 23 print('fun1 释放了 lock_1...') 24 print('end fun1......') 25 26 def fun2(): 27 print('start fun2......') 28 lock_2.acquire() 29 print('fun2 申请了 lock_2...') 30 time.sleep(4) 31 print('fun2 等待 lock_1...') 32 lock_1.acquire() 33 print('fun2 申请了 lock_1...') 34 lock_2.release() 35 print('fun2 释放了 lock_2...') 36 lock_1.release() 37 print('fun2 释放了 lock_1...') 38 print('end fun2......') 39 40 def main(): 41 print('main begining......') 42 t1 = threading.Thread(target = fun1,args = ()) 43 t2 = threading.Thread(target = fun2,args = ()) 44 t1.start() 45 t2.start() 46 t1.join() 47 t2.join() 48 print('main end......') 49 50 if __name__ == '__main__': 51 main()
main begining......
start fun1......
fun1 申请了 lock_1...
start fun2......
fun2 申请了 lock_2...
fun1 等待 lock_2...
fun2 等待 lock_1...
fun1 申请 lock_2 失败
fun1 释放了 lock_1...
end fun1......
fun2 申请了 lock_1...
fun2 释放了 lock_2...
fun2 释放了 lock_1...
end fun2......
main end......
使用timeout(t),如果在t时间内没有申请到该锁,则放弃申请继续下一步
十三.线程处理方法
案例1:
1 import time 2 import threading 3 4 def fun(): 5 print('FUN START AT',time.ctime()) 6 time.sleep(3) 7 print('FUN END AT',time.ctime()) 8 9 if __name__ == '__main__': 10 print('MAIN BEGIN AT',time.ctime()) 11 t = threading.Timer(6,fun) 12 t.start() 13 t.join() 14 print('MAIB DONE AT',time.ctime())
MAIN BEGIN AT Sat Aug 25 20:31:14 2018 FUN START AT Sat Aug 25 20:31:20 2018 FUN END AT Sat Aug 25 20:31:23 2018 MAIB DONE AT Sat Aug 25 20:31:23 2018
timer:利用多线程,在指定时间之后启动一个功能
案例2:
未使用可重入锁
1 import time 2 import threading 3 4 class My_Thread(threading.Thread): 5 def run(self): 6 global num 7 time.sleep(1) 8 if suo.acquire(): 9 num += 1 10 msg = self.name + ' set to num ' + str(num) 11 print(msg) 12 suo.acquire() 13 suo.release() 14 suo.release() 15 16 def main(): 17 for i in range(1,6): 18 print('START ',i) 19 t = My_Thread() 20 t.start() 21 print('END ',i,'\n') 22 23 num = 0 24 suo = threading.Lock() 25 26 if __name__ == '__main__': 27 main()
START 1 END 1 START 2 END 2 START 3 END 3 START 4 END 4 START 5 END 5 Thread-3 set to num 1
案例3:
可重入锁
1 import time 2 import threading 3 4 class My_Thread(threading.Thread): 5 def run(self): 6 global num 7 time.sleep(1) 8 if suo.acquire(): 9 num += 1 10 msg = self.name + ' set to num ' + str(num) 11 print(msg) 12 suo.acquire() 13 suo.release() 14 suo.release() 15 16 def main(): 17 for i in range(1,6): 18 print('START ',i) 19 t = My_Thread() 20 t.start() 21 print('END ',i,'\n') 22 23 num = 0 24 suo = threading.RLock() 25 26 if __name__ == '__main__': 27 main()
START 1 END 1 START 2 END 2 START 3 END 3 START 4 END 4 START 5 END 5 Thread-3 set to num 1 Thread-5 set to num 2 Thread-1 set to num 3 Thread-4 set to num 4 Thread-2 set to num 5
将Lock改为RLock,即为可重入锁
使用可重入锁后,一个锁可以被一个线程多次申请
案例4:
加入join()的可重入锁
1 import time 2 import threading 3 4 class My_Thread(threading.Thread): 5 def run(self): 6 global num 7 time.sleep(1) 8 if suo.acquire(): 9 num += 1 10 msg = self.name + ' set to num ' + str(num) 11 print(msg) 12 suo.acquire() 13 suo.release() 14 suo.release() 15 16 def main(): 17 for i in range(1,6): 18 print('START ',i) 19 t = My_Thread() 20 t.start() 21 t.join() 22 print('END ',i,'\n') 23 24 num = 0 25 suo = threading.RLock() 26 27 if __name__ == '__main__': 28 main()
START 1 Thread-1 set to num 1 END 1 START 2 Thread-2 set to num 2 END 2 START 3 Thread-3 set to num 3 END 3 START 4 Thread-4 set to num 4 END 4 START 5 Thread-5 set to num 5 END 5
案例二三中,线程的顺序是随机的
在加入join()之后,开始排序
案例5:
1 import time 2 import threading 3 4 sign = threading.Semaphore(3) 5 def fun(): 6 if sign.acquire(): 7 for i in range(5): 8 print(threading.currentThread().getName() + 'get Semaphore') 9 time.sleep(5) 10 sign.release() 11 print(threading.currentThread().getName() + 'release Semaphore') 12
13 def main():
14 for i in range(9): 15 t = threading.Thread(target = fun,args = ()) 16 t.start() 17 18 if __name__ == '__main__': 19 main()
Thread-1get Semaphore Thread-1get Semaphore Thread-1get Semaphore Thread-1get Semaphore Thread-1get Semaphore Thread-2get Semaphore Thread-2get Semaphore Thread-2get Semaphore Thread-2get Semaphore Thread-2get Semaphore Thread-3get Semaphore Thread-3get Semaphore Thread-3get Semaphore Thread-3get Semaphore Thread-3get Semaphore Thread-2release Semaphore Thread-3release Semaphore Thread-4get Semaphore Thread-4get Semaphore Thread-4get Semaphore Thread-4get Semaphore Thread-4get Semaphore Thread-5get Semaphore Thread-5get Semaphore Thread-1release Semaphore Thread-5get Semaphore Thread-6get Semaphore Thread-6get Semaphore Thread-6get Semaphore Thread-6get Semaphore Thread-6get Semaphore Thread-5get Semaphore Thread-5get Semaphore Thread-4release Semaphore Thread-7get Semaphore Thread-7get Semaphore Thread-7get Semaphore Thread-7get Semaphore Thread-7get Semaphore Thread-5release Semaphore Thread-8get Semaphore Thread-8get Semaphore Thread-8get Semaphore Thread-8get Semaphore Thread-8get Semaphore Thread-6release Semaphore Thread-9get Semaphore Thread-9get Semaphore Thread-9get Semaphore Thread-9get Semaphore Thread-9get Semaphore Thread-9release Semaphore Thread-7release Semaphore Thread-8release Semaphore
Semaphore:允许一个资源最多有几个多线程同时使用
十四.线程替代方法
- subprocess
- 完全跳过线程,使用进程
- 是派生进程的主要替代方案
- python2.4后引入
- multiprocessiong
- 使用threadiing借口派生,使用子进程
- 允许为多核或者多cpu派生进程,接口跟threading非常相似
- python2.6
- concurrent.futures
- 新的异步执行模块
- 任务级别的操作
- python3.2后引入