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 ...
随机推荐
- python 获取表单的三种方式
条件:urls.py文件中配置好url的访问路径.models.py文件中有Business表. 在views.py文件中实现的三种方式: from app01 improt models def b ...
- CF_Edu.#51_Div.2_1051F_The Shortest Statement
F. The Shortest Statement time limit per test:4 seconds memory limit per test:256 megabytes input:st ...
- 转:CentOS7 常用命令集合
这两天一直在对CentOS 7.2进行初体验,各种学习命令肿么用,不过其实大多和DOS是一样的,只是命令的表达上可能有点儿不一样,毕竟这些都不是一家出来的嘛~ 废话不多说,直接上命令和解析! 常用 ...
- 吴裕雄--天生自然KITTEN编程:切换角色
- ActiveMQ学习总结(一)
自己写的网上商城项目中使用了ActiveMQ,虽然相比于RabbitMQ,kafka,RocketMQ等相比,ActiveMQ可能性能方面不是最好的选择,不过消息队列其实原理区别不大,这里对学过的关于 ...
- vagrant 虚拟机配置最佳实践
Mac VirtualBox Vagrant 管理虚拟机 这篇文章定位是在理解了 vagrant 相关概念之后,教你如何灵活玩转自己的虚拟机配置 本文为 @favoorr 常用的 Mac Virtua ...
- Python知识点汇总
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...
- 自动清理IIS log 日志脚本
系统环境:windows server 2012 r2 IIS 版本:IIS8 操作实现清理IIS log File 脚本如下: @echo off ::自动清理IIS Log file set lo ...
- 从头认识js-js的发展历史
JavaScript简介 JavaScript诞生于1995年,当时,它的主要目的是处理以前有服务端语言(如Perl)负责的一些输入验证操作. JavaScript简史 1995年2月当时就职于Net ...
- 7-45 jmu-python-涨工资 (10 分)
输入一组工资数据,写入列表.对于小于5000的工资,涨1.5倍.并输出涨后的工资数据. 输入格式: 数据之间空格隔开 输出格式: 涨工资后的数据,空格隔开.尾部 不带空格. 输入样例: 3000 40 ...