Python并发编程-多进程
Python并发编程-多进程
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.多进程相关概念
由于Python的GIL全局解释器锁存在,多线程未必是CPU密集型程序的好的选择。
多进程可以完全独立的进程环境中运行程序,可以较充分地利用多处理器。
但是进程本身的隔离带来的数据不共享也是一个问题。而且线程比进程轻量级。
二.multiprocessing
#!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import multiprocessing
import datetime """
Process类遵循了Thread类的API,减少了学习难度。 相比线程的方法,进程多出来几个方法需要注意下:
pid:
进程id
exitcode:
进程的退出状态码
terminate():
终止指定的进程 先看一个例子,前面介绍的单线程、多线程比较的例子的多进程版本,具体代码如下所示。
""" def calc(i):
sum = 0
for _ in range(1000000000):
sum += 1
return i,sum if __name__ == '__main__':
start = datetime.datetime.now() ps = [] for i in range(4):
p = multiprocessing.Process(target=calc,args=(i,),name="calc-{}".format(i))
ps.append(p)
p.start() for p in ps:
p.join()
print(p.name,p.exitcode) delta = (datetime.datetime.now() - start).total_seconds()
print(delta) for p in ps:
print(p.name,p.exitcode) print("=== end ===")
calc-
calc-
calc-
calc-
47.011848
calc-
calc-
calc-
calc-
=== end ===
以上代码执行结果戳这里
三.进程间同步
Python在进程间同步提供了和线程同步一样的类,使用的方法一样,使用的效果也类似。
不过,进程间代价要高于线程间,而且系统底层实现是不同的,只不过Python屏蔽了这些不同之处,让用户简单使用多进程。
multiprocessing还提供共享内存、服务器进程来共享数据,还提供了用于进程间通讯的Queue队列,Pipe管道。
通信方式不同
.多进程就是启动多个解释器进程,进程间通信必须序列化、反序列化
.数据的线程安全性问题
如果每个进程中没有实现多线程,即每个进程仅有一个线程,此时GIL可以说没什么用了。
四.进程池举例
1>.multiprocessing.Pool 是进程池类
multiprocessing.Pool 是进程池类,他有很多方法,具体如下:
apply(self, func, args=(), kwds={}):
阻塞执行,导致主进程执行其他子进程就像一个个执行
apply_async(self, func, args=(), kwds={},callback=None, error_callback=None):
与apply方法用法一致,非阻塞异步执行,得到结果后会执行回调
close():
关闭池,池不能再接受新的任务,所有任务完成后退出进程
terminate():
立即结束工作进程,不再处理未处理的任务
join():
主进程阻塞等待子进程的退出, join方法要在close或terminate之后使用
2>.同步调用
#!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import logging
import datetime
import multiprocessing
# 日志打印进程id、进程名、线程id、线程名
logging.basicConfig(level=logging.INFO, format="%(process)d %(processName)s %(thread)d %(message)s")
def calc(i):
sum = 0
for _ in range(1000000000): # 10亿
sum += 1
logging.info(sum)
return i,sum # 进程要return,才可以拿到这个结果 if __name__ == '__main__': # 注意一定要有这一句
start = datetime.datetime.now() pool = multiprocessing.Pool(4) for i in range(4):
# 返回值,同步调用,注意观察CPU使用
ret = pool.apply(calc, args=(i,))
print(ret)
pool.close()
pool.join() delta = (datetime.datetime.now() - start).total_seconds()
print(delta)
print('===end====')
calc-0 0
calc-1 0
calc-2 0
calc-3 0
50.399442
calc-0 0
calc-1 0
calc-2 0
calc-3 0
=== end ===
以上代码执行结果戳这里
3>.异步调用
#!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import logging
import datetime
import multiprocessing
# 日志打印进程id、进程名、线程id、线程名
logging.basicConfig(level=logging.INFO, format="%(process)d %(processName)s %(thread)d %(message)s") def calc(i):
sum = 0
for _ in range(1000000000): # 10亿
sum += 1
logging.info(sum)
return i, sum # 进程要return,callback才可以拿到这个结果 if __name__ == '__main__':
start = datetime.datetime.now() # 注意一定要有这一句
pool = multiprocessing.Pool(4)
for i in range(4):
# 异步拿到的返回值是什么?
ret = pool.apply_async(calc, args=(i,))
print(ret, '~~~~~~~') # 异步,如何拿到真正的结果呢?
pool.close()
pool.join()
delta = (datetime.datetime.now() - start).total_seconds()
print(delta)
print('===end====')
<multiprocessing.pool.ApplyResult object at 0x000001F02D3230C8> ~~~~~~~
<multiprocessing.pool.ApplyResult object at 0x000001F02D3231C8> ~~~~~~~
<multiprocessing.pool.ApplyResult object at 0x000001F02D323308> ~~~~~~~
<multiprocessing.pool.ApplyResult object at 0x000001F02D3233C8> ~~~~~~~
5828 SpawnPoolWorker-4 7608 1000000000
7248 SpawnPoolWorker-3 5168 1000000000
2020 SpawnPoolWorker-1 2252 1000000000
1620 SpawnPoolWorker-2 3128 1000000000
47.058129
===end====
以上代码执行结果
4>.异步调用,拿最终结果
#!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import logging
import datetime
import multiprocessing # 日志打印进程id、进程名、线程id、线程名
logging.basicConfig(level=logging.INFO, format="%(process)d %(processName)s %(thread)d %(message)s") def calc(i):
sum = 0
for _ in range(1000000000): # 10亿
sum += 1
logging.info(sum)
return i, sum # 进程要return,callback才可以拿到这个结果 if __name__ == '__main__':
start = datetime.datetime.now() # 注意一定要有这一句 pool = multiprocessing.Pool(4) for i in range(4):
#异步拿到的返回值是什么?回调起了什么作用?
ret = pool.apply_async(calc, args=(i,),callback=lambda ret: logging.info('{} in callback'.format(ret)))
print(ret, '~~~~~~~') pool.close()
pool.join()
delta = (datetime.datetime.now() - start).total_seconds()
print(delta)
print('===end====')
<multiprocessing.pool.ApplyResult object at 0x0000017D9709F308> ~~~~~~~
<multiprocessing.pool.ApplyResult object at 0x0000017D9709F448> ~~~~~~~
<multiprocessing.pool.ApplyResult object at 0x0000017D9709F508> ~~~~~~~
<multiprocessing.pool.ApplyResult object at 0x0000017D9709F5C8> ~~~~~~~
8964 SpawnPoolWorker-1 1620 1000000000
572 MainProcess 8184 (0, 1000000000) in callback
992 SpawnPoolWorker-2 2484 1000000000
572 MainProcess 8184 (1, 1000000000) in callback
10608 SpawnPoolWorker-3 2404 1000000000
572 MainProcess 8184 (2, 1000000000) in callback
3268 SpawnPoolWorker-4 8684 1000000000
572 MainProcess 8184 (3, 1000000000) in callback
44.991332
===end====
以上代码执行结果戳这里
五.多进程、多线程的选择
1>.CPU密集型
CPython中使用到了GIL,多线程的时候锁相互竞争,且多核优势不能发挥,选用Python多进程效率更高。
2>.IO密集型
在Python中适合是用多线程,可以减少多进程间IO的序列化开销。且在IO等待的时候,切换到其他线程继续执行,效率不错。
3>.应用
请求/应答模型:WEB应用中常见的处理模型
master启动多个worker工作进程,一般和CPU数目相同。发挥多核优势。
worker工作进程中,往往需要操作网络IO和磁盘IO,启动多线程,提高并发处理能力。worker处理用户的请求,往往需要等待数据,处理完请求还要通过网络IO返回响应。
这就是nginx工作模式。
六.Linux的特殊进程(在Linux/Unix中,通过父进程创建子进程。)
1>.僵尸进程
一个进程使用了fork创建了子进程,如果子进程终止进入僵死状态,而父进程并没有调用wait或者waitpid获取子进程的状态信息,那么子进程仍留下一个数据结构保存在系统中,这种进程称为僵尸进程。
僵尸进程会占用一定的内存空间,还占用了进程号,所以一定要避免大量的僵尸进程产生。有很多方法可以避免僵尸进程。
2>.孤儿进程
父进程退出,而它的子进程仍在运行,那么这些子进程就会成为孤儿进程。孤儿进程会被init进程(进程号为1)收养,并由init进程对它们完成状态收集工作。
init进程会循环调用wait这些孤儿进程,所以,孤儿进程没有什么危害。
3>.守护进程
它是运行在后台的一种特殊进程。它独立于控制终端并周期性执行某种任务或等待处理某些事件。
守护进程的父进程是init进程,因为其父进程已经故意被终止掉了。
守护进程相对于普通的孤儿进程需要做一些特殊处理。
Python并发编程-多进程的更多相关文章
- python并发编程&多进程(二)
前导理论知识见:python并发编程&多进程(一) 一 multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_cou ...
- python并发编程&多进程(一)
本篇理论居多,实际操作见: python并发编程&多进程(二) 一 什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行) ...
- python 并发编程 多进程 目录
python multiprocessing模块 介绍 python 开启进程两种方法 python 并发编程 查看进程的id pid与父进程id ppid python 并发编程 多进程 Proce ...
- python 并发编程 多进程 队列目录
python 并发编程 多进程 队列 python 并发编程 多进程 生产者消费者模型介绍 python 并发编程 多进程 生产者消费者模型总结 python 并发编程 多进程 JoinableQue ...
- python 并发编程 多进程 互斥锁 目录
python 并发编程 多进程 互斥锁 模拟抢票 互斥锁与join区别
- python 并发编程 多进程 生产者消费者模型介绍
一 生产者消费者模型介绍 为什么要使用生产者消费者模型 生产者指的是生产数据的任务,消费者指的是处理数据的任务, 生产数据目的,是为了给消费者处理. 在并发编程中,如果生产者处理速度很快,而消费者处理 ...
- python 并发编程-- 多进程
一 multiprocessing 模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程 ...
- python 并发编程 多进程 互斥锁
运行多进程 每个子进程的内存空间是互相隔离的 进程之间数据不能共享的 一 互斥锁 但是进程之间都是运行在一个操作系统上,进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终 ...
- Python并发编程-多进程socketserver简易版
普通版的socketserver #server.py import socket sk = socket.socket() sk.bind(('127.0.0.1',8080))#建立连接 sk.l ...
随机推荐
- Kafka高级设计和架构,一文深化理解
主题: 1.kafka是写磁盘还是写内存? 2.kafka究竟是由 consumer 从 broker 那里拉数据,还是由 broker 将数据推到 consumer? 3.如何区分已消费(consu ...
- Kafka限流
1. 客户端认证 如果kafka客户端是认证的,那么可以使用userId和clientId两种认证方式.如果没有认证只能使用clientId限流. bin/kafka-configs. --alter ...
- 快速安装Python3+RobotFrameowork自动化测试环境
1. 安装Python3(笔者这里安装的Python3.6.5) 安装 robotframework : pip install robotframework -U pip install rob ...
- [转]10 Best GTK Themes for Ubuntu 18.04
原文地址:https://omgfoss.com/10-best-gtk-themes-ubuntu-18-04/
- react一些问题
一.死循环 1.问题描述 function handleClick() { this.setState({count: ++this.state.count}); console.log(" ...
- Web API之Web Components
本文参考<你的前端框架要被web组件替代了>. 于2011年面世的Web Components是一套功能组件,让开发者可以使用 HTML.CSS 和 JavaScript 创建可复用的组件 ...
- c++动态链接问题
https://blog.csdn.net/liu0808/article/details/81169173 https://blog.csdn.net/f110300641/article/deta ...
- Emiya 家今天的饭
\(dp_{i,j,k}\)表示前\(i\)种烹饪方法,假设最多的是食材\(j\),食材\(j\)比其他食材多\(k\)次出现 其中\(i \in [1,n],j \in [1,m],k \in [- ...
- JAVA知识点总结篇(二)
数组 一维数组 声明 数据类型[] 数组名: 数据类型 数组名[]: 分配空间 数组名 = new 数据类型 [数组长度]: 可以在声明的同时分配空间,分配空间之后数组中才能放数据,数组元素都是通过下 ...
- Source Insight4.0软件破解版
安装source insightt4.0 1.将下载好的sourceinsight4.exe替换安装在program file(x86)目录下的sourceinsight4.exe; 2.启动sour ...