1. 信号量
信号量本质上还是锁,只不过这个锁有很多把钥匙,同一时间只允许有限个线程进程操作(实现有限个数据的并发),但是线程数开了很多个的(信号量的参数不是开的线程数。只是代表同一时间允许并发的线程数)
from threading import Thread from threading import Semaphore # 线程中导入信号量(其实本质还是锁,只不过一把锁可以有多把钥匙) import time import random def func(sem,i): # 开的子线程需要执行的函数 sem.acquire() print("Thread--%s--start" % i) time.sleep(random.random()) print("Thread--%s-done"%i) sem.release() start=time.time() # 统计开多个线程执行ffunc()函数的时间 sem=Semaphore(4) # 同一时间只能有4个线程操作数据(最多实现四个线程并发)这里的并发其实也不是真正意义的并发,只是时间片轮转,宏观上的并发,因为GIL t_lst=[] # 把开的多个线程放在列表中,最后统一join()(其实就是想主线程等待子线程执行完毕)同时保证多个子线程是并发执行的 for i in range(10): t=Thread(target=func,args=(sem,i)) t.start() # 其实是一下开了10个线程,但是由于信号量参数4 同一时间只允许四个线程同时操作(并发) t_lst.append(t) [t.join() for t in t_lst] # 主线程需要等待所有子线程执行完毕(主线程与子线程之间是同步)但是多个子线程之间仍然是异步并发 print("开了10个线程,但是同一时间只允许四个线程并发(使用了信号量)的时间为:%f"%(time.time()-start))
运行结果:
信号量与线程池的异同点:
相同:在信号量的acquire之后,同一时间只能有有限个线程(信号量的参数)同时操作数据,线程池也是同一时间同一时间只能有有限个线程操作数据;
不同点: 信号量是开了很多个线程,但是同一时间只能有信号量的参数个线程操作数据,而线程池是只开了(线程池中参数)个线程,这些线程轮流着执行任务,并没有开很多个线程;信号量是有几个任务就开几个线程,只不过这些线程不能同时执行而已;
对有信号量限制的多个线程可以实现高并发(比如开了100个线程,但是信号量是4)只有被信号量acquire 和 release之间的代码才被限制为有限个线程执行,但是其余的代码其实还是可以实现高并发的(有多少个线程就有多少个线程并发执行)但是线程池就是线程执行的函数内的代码只有线程池的参数个线程并发执行:
from threading import Thread from threading import Semaphore # 线程中导入信号量(其实本质还是锁,只不过一把锁可以有多把钥匙) import time import random def func(sem,i): # 开的子线程需要执行的函数 print("这部分的代码,有信号量的代码其实是可以实现多个线程(10)高并发的,因为这部分代码并没有加锁") time.sleep(3) print("但是对于线程池,就真的只开了(线程池的参数)个线程,所以这部分的代码也是只有有限个线程并发,并没有实现10个线程并发执行这段代码") sem.acquire() print("Thread--%s--start" % i) time.sleep(random.random()) print("Thread--%s-done"%i) sem.release() start=time.time() # 统计开多个线程执行ffunc()函数的时间 sem=Semaphore(4) # 同一时间只能有4个线程操作数据(最多实现四个线程并发)这里的并发其实也不是真正意义的并发,只是时间片轮转,宏观上的并发,因为GIL t_lst=[] # 把开的多个线程放在列表中,最后统一join()(其实就是想主线程等待子线程执行完毕)同时保证多个子线程是并发执行的 for i in range(10): t=Thread(target=func,args=(sem,i)) t.start() # 其实是一下开了10个线程,但是由于信号量参数4 同一时间只允许四个线程同时操作(并发) t_lst.append(t) [t.join() for t in t_lst] # 主线程需要等待所有子线程执行完毕(主线程与子线程之间是同步)但是多个子线程之间仍然是异步并发 print("开了10个线程,但是同一时间只允许四个线程并发(使用了信号量)的时间为:%f"%(time.time()-start))
其实信号量并不影响线程或者进程的并发,只是在枷锁的阶段进行流量限制;