多线程与线程池
Posted daviddd
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程与线程池相关的知识,希望对你有一定的参考价值。
多线程
1,GIL全局解释器锁
- python GIL:(Global Interpret Lock)全局解释器锁
- CPython解释器自动加载GIL锁,基于单核CPU的GIL锁,为了保证数据的安全,单个进程的多线程不能利用多核,即可以并发,但是不能并行,多个进程可以并发,并行
- JPython,PYPY没有GIL锁
- 进入多核时代,GIL锁则成了python的一个弱点
- 以为CPython解释器所有的业务逻辑都是围绕单个线程实现的,去掉这个GIL锁,几乎不可能
2,GIL与lock 的区别
- 相同点:都是互斥锁,
- 不同点:
- GIL是全局解释器锁,保护的是解释器内部的资源数据安全
- GIL锁的上锁和释放无序手动操作
- Lock:自己代码中定义的互斥锁,保护进程中的资源数据安全,需手动加锁,手动释放
密集型,IO密集型的效率
1,计算密集型:
多进程的并发并行效率高
from threading import Thread from multiprocessing import Process import time import random # # 计算密集型: 单个进程的多线程并发 vs 多个进程的并发并行 # # def task(): # count = 0 # for i in range(10000000): # count += 1 # # # if __name__ == '__main__': # # # 多进程的并发,并行 # # start_time = time.time() # # l1 = [] # # for i in range(4): # # p = Process(target=task,) # # l1.append(p) # # p.start() # # # # for p in l1: # # p.join() # # # # print(f'执行效率:{time.time()- start_time}') # 3.1402080059051514 # # # 多线程的并发 # # start_time = time.time() # # l1 = [] # # for i in range(4): # # p = Thread(target=task,) # # l1.append(p) # # p.start() # # # # for p in l1: # # p.join() # # # # print(f'执行效率:{time.time()- start_time}') # 4.5913777351379395
2,IO密集型:
单个进程的多线程的多线程的并发效率高
def task(): count = 0 time.sleep(random.randint(1,3)) count += 1 # if __name__ == '__main__': # 多进程的并发,并行 # start_time = time.time() # l1 = [] # for i in range(50): # p = Process(target=task,) # l1.append(p) # p.start() # # for p in l1: # p.join() # # print(f'执行效率:{time.time()- start_time}') # 8.000000000 # 多线程的并发 # start_time = time.time() # l1 = [] # for i in range(50): # p = Thread(target=task,) # l1.append(p) # p.start() # # for p in l1: # p.join() # # print(f'执行效率:{time.time()- start_time}') # 3.0294392108917236
多线程实现socket通信
多线程的存在实现了socket真正的通信
服务端:
import socket from threading import Thread def is_accept(): server = socket.socket() server.bind(('127.0.0.1',8848)) server.listen(5) while 1: conn,addr = server.accept() t = Thread(target=communicate, args=(conn,addr)) t.start() def communicate(conn,addr): while 1: try: from_client_data = conn.recv(1024) print(f'来自{addr}客户端的消息:{from_client_data.decode("utf-8")}') to_client_data = input('>>>>>>') conn.send(to_client_data.encode('utf-8')) except ConnectionError: break conn.close()
客户端
import socket client = socket.socket() client.connect(('127.0.0.1', 8848)) while 1: to_client_data = input('>>>>>>').strip() client.send(to_client_data.encode('utf-8')) from_client_data = client.recv(1024) print(f'来自服务端的消息:{from_client_data.decode("utf-8")}') client.close()
进程池,线程池
python标准模块:concurrent.futures———并发未来
concurent.future模块需要了解的 1.concurent.future模块是用来创建并行的任务,提供了更高级别的接口, 为了异步执行调用 2.concurent.future这个模块用起来非常方便,它的接口也封装的非常简单 3.concurent.future模块既可以实现进程池,也可以实现线程池 4.模块导入进程池和线程池 from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor 还可以导入一个Executor,但是你别这样导,这个类是一个抽象类 抽象类的目的是规范他的子类必须有某种方法(并且抽象类的方法必须实现),但是抽象类不能被实例化 5. p = ProcessPoolExecutor(max_works)对于进程池如果不写max_works:默认的是cpu的数目,默认是4个 p = ThreadPoolExecutor(max_works)对于线程池如果不写max_works:默认的是cpu的数目*5 6.如果是进程池,得到的结果如果是一个对象。我们得用一个.get()方法得到结果 但是现在用了concurent.future模块,我们可以用obj.result方法 p.submit(task,i) #相当于apply_async异步方法 p.shutdown() #默认有个参数wite=True (相当于close和join)
进程池:就是在一个进程内控制一定个数的线程
基于concurrent.futures模块的进程池和线程池,他们的同步执行和异步执行是一样
以上是关于多线程与线程池的主要内容,如果未能解决你的问题,请参考以下文章
newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段