Python3学习之路~10.1 多进程、进程间通信、进程池
一 多进程multiprocessing
multiprocessing is a package that supports spawning processes using an API similar to the threading module. The multiprocessing package offers both local and remote concurrency, effectively side-stepping the Global Interpreter Lock by using subprocesses instead of threads. Due to this, the multiprocessing module allows the programmer to fully leverage multiple processors on a given machine. It runs on both Unix and Windows.
import multiprocessing,time def run(name):
print("hello",name)
time.sleep(2) if __name__ == '__main__': for i in range(10):
p = multiprocessing.Process(target=run,args=('Bob %s'%i,))
p.start()
import multiprocessing,time,threading def thread_run():
print(threading.get_ident()) #线程号 def run(name):
print("hello",name)
t = threading.Thread(target=thread_run,)
t.start()
time.sleep() if __name__ == '__main__': for i in range():
p = multiprocessing.Process(target=run,args=('Bob %s'%i,))
p.start()
可以在进程中起线程
# 在主进程里调用了info,在子进程了又调用了info,我们看看效果?
# 可以看到,每一个进程都是由父进程启动的。主程序的父进程是pyCharm,子进程的父进程是主进程。 from multiprocessing import Process
import os def info(title):
print(title)
print('module name:', __name__)
print('parent process:', os.getppid()) #得到父进程ID
print('process id:', os.getpid()) #得到进程ID
print("\n\n") def f(name):
info('\033[31;1mfunction f\033[0m')
print('hello', name) if __name__ == '__main__':
info('\033[32;1mmain process line\033[0m')
p = Process(target=f, args=('bob',))
p.start()
p.join() #####输出:
####ain process line
####odule name: __main__
####arent process: 8268
####rocess id: 4448 ####unction f
####odule name: __mp_main__
####arent process: 4448
####rocess id: 9596 ####ello bob
得到进程ID
二 进程间通信
不同进程间内存是不共享的,要想实现两个进程间的数据交换,可以用以下方法:
1.Queues
首先我们知道,线程之间是数据共享的,子线程放进queue数据,父线程可以取出来。如下示例
import threading,queue def f():
q.put([42,None,'hello']) if __name__ == '__main__':
q = queue.Queue()
t = threading.Thread(target=f)
t.start()
print(q.get()) ####输出:[42, None, 'hello']
线程之间数据共享
把线程改为进程,会发现报错。
import multiprocessing,queue def f():
q.put([42,None,'hello']) if __name__ == '__main__':
q = queue.Queue()
p = multiprocessing.Process(target=f)
p.start()
print(q.get()) ####输出报错:NameError: name 'q' is not defined
将线程改为进程,尝试数据传输,报错NameError: name 'q' is not defined
报错的原因是进程之间数据不共享。子进程和父进程分别拥有独立的内存空间,所以子进程是访问不了父进程的queue的。那有什么办法可以使子进程访问到父进程的queue呢?我们可以尝试将这个queue当做变量传给子进程。发现还是报错。
import multiprocessing,queue def f(q):
q.put([42,None,'hello']) if __name__ == '__main__':
q = queue.Queue()
p = multiprocessing.Process(target=f,args=(q,))
p.start()
print(q.get()) ####输出报错:TypeError: can't pickle _thread.lock objects
将线程queue传递给子进程是不可以的,报错TypeError: can't pickle _thread.lock objects
报错的原因是我们错将线程queue(通过import queue引入)传递给了子进程,实际上我们传递给子进程的应该是进程queue(通过from multiprocessing import Queue引入)。接下来才是正确的示例:
from multiprocessing import Process,Queue #引入进程queue def f(q):
q.put([42,None,'hello']) #子进程放入数据 if __name__ == '__main__':
q = Queue()
p = Process(target=f,args=(q,)) #将q传递给子进程
p.start()
print(q.get()) #主进程取出数据 ####输出:[42, None, 'hello']
上面的例子,我们把进程queue传递给了子进程,表面上看,子进程和父进程共用一个queue,实际上并不是这样,而是子进程克隆了一个父进程的queue,子进程将数据放入克隆queue中,克隆queue将其序列化保存,然后进行反序列化后放到父进程的原始queue中,所以严格意义上子进程和父进程的queue并不是一个共享queue。
2.Pipes
要想实现两个进程间的数据传递,除了Queues,还可以使用Pipes。
Pipe()返回的两个连接对象代表管道的两端。 每个连接对象都有send()和recv()方法(以及其他方法)。
from multiprocessing import Process, Pipe def f(conn):
conn.send([42, None, 'hello'])
print('from parent:',conn.recv())
conn.close() if __name__ == '__main__':
parent_conn, child_conn = Pipe()
p = Process(target=f, args=(child_conn,))
p.start()
print('from son:',parent_conn.recv())
parent_conn.send('hello')
p.join()
3.Managers
Queues和Pipes仅能实现两个进程之间的数据传递,而Managers可以实现进程之间数据的共享。
A manager object returned by Manager() controls a server process which holds Python objects and allows other processes to manipulate them using proxies.
A manager returned by Manager() will support types list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value and Array. For example,
from multiprocessing import Process, Manager
import os def f(d,l):
d[os.getpid()] = os.getpid()
l.append(os.getpid())
print(l) if __name__ == '__main__':
with Manager() as manager:
d = manager.dict() #生成一个字典,可在多个进程间共享和传递
l = manager.list(range(5)) #生成一个列表,可在多个进程间共享和传递
p_list = []
for i in range(10):
p = Process(target=f,args=(d,l))
p.start()
p_list.append(p)
for res in p_list: #等待结果
res.join() print(d)
[0, 1, 2, 3, 4, 8512]
[0, 1, 2, 3, 4, 8512, 11060]
[0, 1, 2, 3, 4, 8512, 11060, 4820]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496, 4264]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496, 4264, 8420]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496, 4264, 8420, 9184]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496, 4264, 8420, 9184, 6592]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496, 4264, 8420, 9184, 6592, 9808]
[0, 1, 2, 3, 4, 8512, 11060, 4820, 9496, 4264, 8420, 9184, 6592, 9808, 5064]
{8512: 8512, 11060: 11060, 4820: 4820, 9496: 9496, 4264: 4264, 8420: 8420, 9184: 9184, 6592: 6592, 9808: 9808, 5064: 5064}
输出
进程锁
虽然进程之间是独立运行的,但是对于各进程来说,终端屏幕是共享的,为了防止输出结果时,各个进程争抢输出,造成打印结果混乱,可以给进程加一把锁。
from multiprocessing import Process,Lock def f(l,i):
l.acquire() #得到锁
print("hello world",i)
l.release() #释放锁 if __name__ == '__main__':
lock = Lock() #生成锁的实例 for num in range(10):
Process(target=f,args=(lock,num)).start() #将lock传递给子进程
三 进程池
我们每起一个进程实际上就是克隆一份父进程数据给子进程使用,起多个进程时就会占用很多内存空间。为了节省开销,我们使用进程池。进程池就是限制同一时间有多少个进程运行。
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用进程为止。
进程池中有两个方法:
- apply #同步执行,即串行
- apply_async #异步执行,即并发
from multiprocessing import Pool
import time,os def Foo(i):
time.sleep(2)
print('my processid is ',os.getpid())
return i+100 if __name__ == '__main__': #windows上运行进程池必须加这行代码,否则报错
pool = Pool(5) #运行进程池中同时放入5个进程 for i in range(10):
# pool.apply(func=Foo,args=(i,)) #同步执行,即串行
pool.apply_async(func=Foo, args=(i,)) # 异步执行,即并发,此时有10个进程,同时执行的有5个,其他的挂起 print('end')
pool.close() #注意:一定要先关闭进程池再join
pool.join() #表示等进程池中进程执行完毕后称程序再关闭,如果注释,则程序直接关闭。
下面的例子,实现了主进程起了10个子进程,分别执行Foo函数,每次子进程执行完毕后,父进程回调Bar函数(可观察到执行Bar函数的进程ID与主进程ID相同)。
from multiprocessing import Pool
import time,os def Foo(i):
time.sleep(2)
print('my processid is ',os.getpid())
return i+100 def Bar(arg):
print('--exec done:',arg,'my processid is ',os.getpid()) if __name__ == '__main__': #windows上运行进程池必须加这行代码,否则报错
pool = Pool(5) #运行进程池中同时放入5个进程 for i in range(10):
pool.apply_async(func=Foo, args=(i,),callback=Bar) # callback=回调 print('end',os.getpid())
pool.close() #注意:先close再join
pool.join() #表示等进程池中进程执行完毕后称程序再关闭,如果注释,则程序直接关闭。
Python3学习之路~10.1 多进程、进程间通信、进程池的更多相关文章
- Python3学习之路~10.2 协程、Greenlet、Gevent
		一 协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切 ... 
- Python3学习之路~10.3 论事件驱动与异步IO
		论事件驱动----详见:https://www.cnblogs.com/alex3714/articles/5248247.html Select\Poll\Epoll异步IO----详见:http: ... 
- Python3学习之路~0 目录
		目录 Python3学习之路~2.1 列表.元组操作 Python3学习之路~2.2 简单的购物车程序 Python3学习之路~2.3 字符串操作 Python3学习之路~2.4 字典操作 Pytho ... 
- springboot 学习之路 6(集成durid连接池)
		目录:[持续更新.....] spring 部分常用注解 spring boot 学习之路1(简单入门) spring boot 学习之路2(注解介绍) spring boot 学习之路3( 集成my ... 
- python学习笔记——multiprocessing 多进程组件 进程池Pool
		1 进程池Pool基本概述 在使用Python进行系统管理时,特别是同时操作多个文件目录或者远程控制多台主机,并行操作可以节约大量时间,如果操作的对象数目不大时,还可以直接适用Process类动态生成 ... 
- 2020.9.28 多进程multiprocess 进程池pool 子进程subprocess 进程间通信
		1.multiprocessing模块--跨平台版本的多进程模块 multiprocessing模块提供了一个Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结束: from ... 
- Python 多进程和进程池
		一,前言 进程:是程序,资源集合,进程控制块组成,是最小的资源单位 特点:就对Python而言,可以实现真正的并行效果 缺点:进程切换很容易消耗cpu资源,进程之间的通信相对线程来说比较麻烦 线程:是 ... 
- python多进程,进程池,数据共享,进程通信,分布式进程
		一.操作系统中相关进程的知识 Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊.普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前 ... 
- python多进程,以及进程池并发
		模拟多进程 #!/usr/bin/env python#-*- coding:utf-8 -*-import timefrom multiprocessing import Process def s ... 
随机推荐
- mysql报错2003 ,can't connect to mysql server on “localhost”
			我在安装成功后启动MySQL服务时,服务启动不了,提示:MySQL服务无法启动 服务没有报告任何错误 请键入NET HELPMSG 3534 以获得更多帮助,如下: 解决方案:安装好MySQL后 ... 
- 在linux中自动向设备中安装apk包
			环境:华为手机 linux centos64 为了锻炼自己,我把脚本文件和APK文件放到了不同的路径下. 需求:将虚拟机中的100个apk包安装到手机中. import os,time os.chdi ... 
- 安装python3.5
			安装python3.5可能使用的依赖 [root@heweiwei heweiwei]# yum install openssl-devel bzip2-devel expat-devel gdbm- ... 
- 从一道网易面试题浅谈 Tagged Pointer - darcy_tang 的博客
			前言 这篇博客九月就想写了,因为赶项目拖了到现在,抓住17年尾巴写吧~ 正文 上次看了一篇 <从一道网易面试题浅谈OC线程安全> 的博客,主要内容是: 作者去网易面试,面试官出了一道面试题 ... 
- 一月七笔千万美元投资!国内VR行业在刮什么风?
			虽然直到现在仍然没有一款真正能够彻底普及并改变大众操控方式的虚拟现实设备出现,但其已经被认定是未来人类社会中不可或缺的重要组成部分和工作.生活.娱乐.休闲载体.而虚拟现实设备.内容在今年年初CES展会 ... 
- 通过IE私有滤镜让IE6 7 8支持背景透明,内容不透明效果。
			CSS3已经支持背景rgba的rgba透明度,这一方法可以避免元素内容也随背景一起变透明(详情请阅http://www.cssha.com/css3-new-knowledge-student).但是 ... 
- VI.应用-Trajectory Data Mining
			$textbf{Trajectory Data Mining: An Overview}$ 很好的一篇概述,清晰明了地阐述了其框架,涉及内容又十分宽泛.值得细读. 未完成,需要补充. $textbf{ ... 
- abp框架运行——前后端分离(基于VUE)
			目录 1.介绍abp 2.abp如何工作 3.运行Domo 3.1官网点击 创建Demo 3.2 配置NetCore,选择Vue 3.3 输入系统名称验证码 4.官方手册文档 5.VUE项目 6. S ... 
- ASP.NET CORE 管道模型及中间件使用解读
			说到ASP.NET CORE 管道模型不得不先来看看之前的ASP.NET 的管道模型,两者差异很大,.NET CORE 3.1 后完全重新设计了框架的底层,.net core 3.1 的管道模型更加灵 ... 
- SpringCloud - 全家桶
			先导篇:SpringCloud介绍篇 第一篇:注册中心Eureka 第二篇:服务提供与Rest+Ribbon调用 第三篇:服务提供与Feign调用 第四篇:熔断器Hystrix(断路器) 第五篇:熔断 ... 
