快速了解Python并发编程的工程实现(下)
关于我
一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。
Github:https://github.com/hylinux1024
微信公众号:终身开发者(angrycode)
0x00 使用进程实现并发
上一篇文章介绍了线程的使用。然而Python
中由于Global Interpreter Lock
(全局解释锁GIL
)的存在,每个线程在在执行时需要获取到这个GIL
,在同一时刻中只有一个线程得到解释锁的执行,Python
中的线程并没有真正意义上的并发执行,多线程的执行效率也不一定比单线程的效率更高。
如果要充分利用现代多核CPU
的并发能力,就要使用multipleprocessing
模块了。
0x01 multipleprocessing
与使用线程的threading
模块类似,multipleprocessing
模块提供许多高级API
。最常见的是Pool
对象了,使用它的接口能很方便地写出并发执行的代码。
from multiprocessing import Pool
def f(x):
return x * x
if __name__ == '__main__':
with Pool(5) as p:
# map方法的作用是将f()方法并发地映射到列表中的每个元素
print(p.map(f, [1, 2, 3]))
# 执行结果
# [1, 4, 9]
关于Pool
下文中还会提到,这里我们先来看Process
。
Process
要创建一个进程可以使用Process
类,使用start()
方法启动进程。
from multiprocessing import Process
import os
def echo(text):
# 父进程ID
print("Process Parent ID : ", os.getppid())
# 进程ID
print("Process PID : ", os.getpid())
print('echo : ', text)
if __name__ == '__main__':
p = Process(target=echo, args=('hello process',))
p.start()
p.join()
# 执行结果
# Process Parent ID : 27382
# Process PID : 27383
# echo : hello process
进程池
正如开篇提到的multiprocessing
模块提供了Pool
类可以很方便地实现一些简单多进程场景。
它主要有以下接口
apply(func[, args[, kwds]])
执行func(args,kwds)
方法,在方法结束返回前会阻塞。apply_async(func[, args[, kwds[, callback[, error_callback]]]])
异步执行func(args,kwds)
,会立即返回一个result
对象,如果指定了callback
参数,结果会通过回调方法返回,还可以指定执行出错的回调方法error_callback()
map(func, iterable[, chunksize])
类似内置函数map()
,可以并发执行func
,是同步方法map_async(func, iterable[, chunksize[, callback[, error_callback]]])
异步版本的map
close()
关闭进程池。当池中的所有工作进程都执行完毕时,进程会退出。terminate()
终止进程池join()
等待工作进程执行完,必需先调用close()
或者terminate()
from multiprocessing import Pool
def f(x):
return x * x
if __name__ == '__main__':
with Pool(5) as p:
# map方法的作用是将f()方法并发地映射到列表中的每个元素
a = p.map(f, [1, 2, 3])
print(a)
# 异步执行map
b = p.map_async(f, [3, 5, 7, 11])
# b 是一个result对象,代表方法的执行结果
print(b)
# 为了拿到结果,使用join方法等待池中工作进程退出
p.close()
# 调用join方法前,需先执行close或terminate方法
p.join()
# 获取执行结果
print(b.get())
# 执行结果
# [1, 4, 9]
# <multiprocessing.pool.MapResult object at 0x10631b710>
# [9, 25, 49, 121]
map_async()
和apply_async()
执行后会返回一个class multiprocessing.pool.AsyncResult
对象,通过它的get()
可以获取到执行结果,ready()
可以判断AsyncResult
的结果是否准备好。
进程间数据的传输
multiprocessing
模块提供了两种方式用于进程间的数据共享:队列(Queue
)和管道(Pipe
)
Queue
是线程安全,也是进程安全的。使用Queue
可以实现进程间的数据共享,例如下面的demo
中子进程put
一个对象,在主进程中就能get
到这个对象。
任何可以序列化的对象都可以通过Queue
来传输。
from multiprocessing import Process, Queue
def f(q):
q.put([42, None, 'hello'])
if __name__ == '__main__':
# 使用Queue进行数据通信
q = Queue()
p = Process(target=f, args=(q,))
p.start()
# 主进程取得子进程中的数据
print(q.get()) # prints "[42, None, 'hello']"
p.join()
# 执行结果
# [42, None, 'hello']
Pipe()
返回一对通过管道连接的Connection
对象。这两个对象可以理解为管道的两端,它们通过send()
和recv()
发送和接收数据。
from multiprocessing import Process, Pipe
def write(conn):
# 子进程中发送一个对象
conn.send([42, None, 'hello'])
conn.close()
def read(conn):
# 在读的进程中通过recv接收对象
data = conn.recv()
print(data)
if __name__ == '__main__':
# Pipe()方法返回一对连接对象
w_conn, r_conn = Pipe()
wp = Process(target=write, args=(w_conn,))
rp = Process(target=read, args=(r_conn,))
wp.start()
rp.start()
# 执行结果
# [42, None, 'hello']
需要注意的是,两个进程不能同时对一个连接对象进行send
或recv
操作。
同步
我们知道线程间的同步是通过锁机制来实现的,进程也一样。
from multiprocessing import Process, Lock
import time
def print_with_lock(l, i):
l.acquire()
try:
time.sleep(1)
print('hello world', i)
finally:
l.release()
def print_without_lock(i):
time.sleep(1)
print('hello world', i)
if __name__ == '__main__':
lock = Lock()
# 先执行有锁的
for num in range(5):
Process(target=print_with_lock, args=(lock, num)).start()
# 再执行无锁的
# for num in range(5):
# Process(target=print_without_lock, args=(num,)).start()
有锁的代码将每秒依次打印
hello world 0
hello world 1
hello world 2
hello world 3
hello world 4
如果执行无锁的代码,则在我的电脑上执行结果是这样的
hello worldhello world 0
1
hello world 2
hello world 3
hello world 4
除了Lock
,还包括RLock
、Condition
、Semaphore
和Event
等进程间的同步原语。其用法也与线程间的同步原语很类似。API
使用可以参考文末中引用的文档链接。
在工程中实现进程间的数据共享应当优先使用队列或管道。
0x02 总结
本文对multiprocessing
模块中常见的API
作了简单的介绍。讲述了Process
和Pool
的常见用法,同时介绍了进程间的数据方式:队列和管道。最后简单了解了进程间的同步原语。
通过与上篇的对比学习,本文的内容应该是更加容易掌握的。
0x03 引用
- https://python-parallel-programmning-cookbook.readthedocs.io
- https://docs.python.org/3/library/threading.html
- https://docs.python.org/3.7/library/multiprocessing.html
- https://docs.python.org/3/glossary.html#term-global-interpreter-lock
- https://docs.python.org/3/library/concurrent.futures.html#module-concurrent.futures
快速了解Python并发编程的工程实现(下)的更多相关文章
- 快速了解Python并发编程的工程实现(上)
关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...
- Python并发编程二(多线程、协程、IO模型)
1.python并发编程之多线程(理论) 1.1线程概念 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程(流水线的工作需要电源,电源就相当于 ...
- Python并发编程一(多进程)
1.背景知识(进程.多道技术) 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一 ...
- python并发编程之进程、线程、协程的调度原理(六)
进程.线程和协程的调度和运行原理总结. 系列文章 python并发编程之threading线程(一) python并发编程之multiprocessing进程(二) python并发编程之asynci ...
- python并发编程&多线程(一)
本篇理论居多,实际操作见: python并发编程&多线程(二) 一 什么是线程 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程,一 ...
- python并发编程&多进程(一)
本篇理论居多,实际操作见: python并发编程&多进程(二) 一 什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行) ...
- Python并发编程内容回顾
Python并发编程内容回顾 并发编程小结 目录 • 一.到底什么是线程?什么是进程? • 二.Python多线程情况下: • 三.Python多进程的情况下: • 四.为什么有这把GIL锁? • 五 ...
- Python并发编程-并发解决方案概述
Python并发编程-并发解决方案概述 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.并发和并行区别 1>.并行(parallel) 同时做某些事,可以互不干扰的同一个时 ...
- python并发编程之线程/协程
python并发编程之线程/协程 part 4: 异步阻塞例子与生产者消费者模型 同步阻塞 调用函数必须等待结果\cpu没工作input sleep recv accept connect get 同 ...
随机推荐
- Java 内存映射文件
import java.io.*; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import jav ...
- C# ExcelAddIn 开发笔记
好久都没有写博客了,最近真的是太忙了,接手公司要做的一个小的新的项目,从接触认识到一个新东西,再到自己琢磨研究,最终结合公司业务把整个excel插件项目完成,还是有一点点成就感.以下是项目中基本上大致 ...
- duilib加消息
一.加消息 1. public INotifyUI, 2. void Notify(TNotifyUI& msg); 3. Notify实现 4. m_pManager->AddNoti ...
- STM32-I2C_CheckEvent-标志位自动清除理解
STM32里I2C_CheckEvent函数我们应该是相当熟悉了,在每次发送数据后我们都需要检验相应的EVx(x = 0,1,2,,,)事件是否有发送. 函数定义如下: ErrorStatus I2C ...
- 个人永久性免费-Excel催化剂功能第83波-遍历文件夹内文件信息特别是图像、音视频等特有信息
在过往的功能中,有体现出在Excel上管理文件的极大优势,在文件的信息元数据中,有图片和音视频这两类特有的属性数据,此篇对过往功能的一个补充,特别增加了图片和音视频信息的遍历功能. 使用场景 在文件管 ...
- 万能RecyclerView的数据适配器BaseRecyclerViewAdapterHelper
今天楼主才发现github上有这么一个好用的开源代码,充满好奇心的楼主马上使用了,特地分享给大家. 此项目的github地址: https://github.com/CymChad/BaseRecyc ...
- MVC WebApi 实现Token验证
基于令牌的认证 我们知道WEB网站的身份验证一般通过session或者cookie完成的,登录成功后客户端发送的任何请求都带上cookie,服务端根据客户端发送来的cookie来识别用户. WEB A ...
- js异步解决方法
在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作.在服务器端,"异步模式"甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有ht ...
- web设计_7_页面缺失图片或CSS的情况下仍然易读
1. 在任何可能使用背景图片的地方应设置同样的颜色的背景色. 防止图片不能加载的情况下,页面内容同样保持较好可读性. 例如文字为白色,背景图为深色,如果不设置背景色,当背景图未成功加载, 而浏览器多数 ...
- httpclient信任所有证书解决SSLException:Unrecognized SSL message,plaintext connection
在使用 HttpClient 工具调用第三方 Http 接口时报错 javax.net.ssl.SSLException:Unrecognized SSL message,plaintext conn ...