多进程 multiprocessing
数据的共享,涉及调度问题,要合理使用计算机的资源,进程管理的线程太多就无法管理了,操作系统管理的进程太多也无法实现,合理范围内使用。
多进程的启动要在主模块下
进程都认为自己独占cup资源。由操作系统调度
cpu绑定,利用多核的一二级缓存,加快计算速度,如果切换后对于计算结果的再次调用时间较常,就可以用绑定解决
python中进程接口几乎与线程一样,process类遵循Thread类的API,但是原理完全不同,概念是相同的,但实现完全不同
python中CPU密集型使用进程更好,但如果对C++自己解决内存问题,但速度较python快
import multiprocessing import datetime import logging logging.basicConfig(level=logging.INFO, format="%(process)d %(processName)s %(thread)s %(message)s") def calc(i): sum = 0 for _ in range(10000000): sum += 1 logging.info('{}.in function'.format(sum)) return sum if __name__ == '__main__': start = datetime.datetime.now() pool = multiprocessing.Pool(3) for i in range(3): pool.apply_async(calc, args=(i,), callback=lambda x: logging.info("{}.in callback".format(x))) # p = threading.Thread(target=calc, args=(i,), name="calc-{}".format(i)) pool.close() pool.join() delta = (datetime.datetime.now() - start).total_seconds() print(delta) print("end=========")
以上程序,在使用单线程和多线程时,时间都是4分多,而使用多进程时间只用了1分半左右,这是正真的并行。多线程时不能实现是因为GIL这把解释器进程级别的锁。
代码执行时,注意__name__="__main___" 将执行的代码放在其下。
pid 进程id,进程的唯一ID
exitcode 进程退出状态码, 退出码0是正常,其他退出码是自己写的,不同的操作系统不同,
terminate 终止指定的进程
进程间同步
进程的同步不要使用线程的模块
进程间的同步代价要高于线程间的同步
multiprocessing 进程间的通讯还提供了内存,服务器进程来共享数据。可以使用Queue,pipe管道,但是现在基本不用,使用第三方队列通讯,和网络通讯解决。
多进程就是启动多个解释器进程,进程间的通信,要序列化和反序列化,都比较耗时。
如果进程中都没有多线程,那么GIL不会影响程序。
进程池:
multiprocessing.pool 是进程池类
apply(self, func, args=(), kwds={}) 同步阻塞执行
apply_async 异步非阻塞执行,得到的结果会执行回调callback
close() 关闭池,池不能在接受新任务
terminate() 结束工作进程,不再处理未处理的任务
join() 主进程阻塞等待子进程的退出,join方法要在close或者terminate后使用
async异步 ,sync同步
同步阻塞,等待
异步非阻塞,不等待
callback要求有一个参数,接受进程的返回值
多进程,多线程的选择
1、CPU密集型
CPython 中的GIL,多线程时相互竞争,不能发挥多核的优势,如果要用Python解决,就使用多进程
2、IO密集型,适合使用多线程,可以减去多进程IO切换之间的序列化开销。再IO等待时,切换到其他线程执行,效果很好。
应用
请求应答模型:WEB应用中常见的处理模型
master启动多个worker工作进程,一般和CPU数目相同,发挥多核的优势
worker进程中,往往要处理网络IO和磁盘IO,启动多线程,提高并发处理的能力。worker处理用户的请求,往往需要等到数据,处理完还需要通过网络IO返回响应。
这就是nginx工作模式。