多进程

上一章:Python多线程与多进程(一)

由于GIL的存在,Python的多线程并没有实现真正的并行。因此,一些问题使用threading模块并不能解决

不过Python为并行提供了一个替代方法:多进程。在多进程里,线程被换成一个个子进程。每个进程都运作着各自的GIL(这样Python就可以并行开启多个进程,没有数量限制)。需要明确的是,线程都是同一个进程的组成部分,它们共享同一块内存、存储空间和计算资源。而进程却不会与它们的父进程共享内存,因此进程间通信比线程间通信更为复杂

多进程相比多线程优缺点如下:

优点 缺点
可以使用多核操作系统 更多的内存消耗
进程使用独立的内存空间,避免竞态问题 进程间的数据共享变得更加困难
子进程容易中断 进程间通信比线程困难
避开GIL限制  

  

Python多进程

multiprocessing模块提供了一个Process类,它有点类似多线程模块中threading.Thread类。因此,把多线程代码迁移到多进程还是比较简单的,因为代码的基本结构不变

我们快速演示一个多进程的示例:

import multiprocessing

def run(pname):
print(pname) for i in range(3):
p = multiprocessing.Process(target=run, args=("Process-%s" % i,))
p.start()
p.join()

    

运行结果:

Process-0
Process-1
Process-2

  

可以看出,多进程和多线程的代码非常像,这里需要注意一点,如果是在Windows上执行的需要把启动进程的代码放到if __name__ == "__main__":底下

if __name__ == "__main__":
for i in range(3):
p = multiprocessing.Process(target=run, args=("Process-%s" % i,))
p.start()
p.join()

  

进程退出状态:当进程结束的时候,会产生一个状态码,它是一个数字,表示执行结果,不同数字代表程序运行的不同情况:

  • 等于0表示正常完结
  • 大于0表示异常完结
  • 小于0表示进程被另一个进程通过-1*exit_code信号终结

下面的代码演示如何读取和使用退出码

import multiprocessing
import time def first():
print("There is no problem here") def second():
raise RuntimeError("Error raised!") def third():
time.sleep(3)
print("This process will be terminated") workers = [multiprocessing.Process(target=first), multiprocessing.Process(target=second),
multiprocessing.Process(target=third)]
for w in workers:
w.start() workers[-1].terminate() for w in workers:
w.join() for w in workers:
print(w.exitcode)

  

运行结果:

There is no problem here
Process Process-2:
Traceback (most recent call last):
File "/home/lf/anconda3/lib/python3.6/multiprocessing/process.py", line 258, in _bootstrap
self.run()
File "/home/lf/anconda3/lib/python3.6/multiprocessing/process.py", line 93, in run
self._target(*self._args, **self._kwargs)
File "test01.py", line 11, in second
raise RuntimeError("Error raised!")
RuntimeError: Error raised!
0
1
-15

  

我们注意到,第三个子进程的print语句没有执行,这是因为在sleep方法结束之前进程已经被中止了。还有一点需要注意的是:两个独立的for循环处理三个子进程:一个启动子进程,另一个通过join方法连接进程。如果我们在开启每个子进程时都执行join方法,而不是没有join直接中断第三个进程,那么第三个进程就不会失败。于是第三个子进程返回的退出码也是0,因为和多线程一样,join方法在目标进程完结之前会阻塞子进程的调用  

进程池

多进程模块还提供了pool类,表示一个进程池,里面装有子进程,可以通过不同的方法执行同一组任务。

Pool类的主要方法如下:

  • apply:这个方法在独立的子进程中运行一个函数。它还会在被调用函数返回结果之前阻塞进程
  • apply_async:这个方法会在独立子进程中异步地运行一个函数,就是说进程会立即返回一个ApplyResult对象,要获得真实的返回值需要使用get()方法。get()在异步执行的函数结束之前都会被阻塞
  • map:这个方法对一组数值应用一个函数。它是一个阻塞动作,所以返回值是每个值经过函数映射的列表

进程间通信:进程间通信的方式不像线程间通信那么简单,但是,Python提供了一些工具帮助我们解决问题。

Queue类是一个既线程安全又进程安全的先进先出(FIFO)数据交换机制。multiprocessing提供的Queue类基本是Queue.Queue的克隆版本,因此二者API基本相同

from multiprocessing import Queue, Process
import random def generate(q):
while True:
value = random.randrange(10)
q.put(value)
print("Value added to queue: %s" % (value)) def reader(q):
while True:
value = q.get()
print("Value from queue: %s" % (value)) queue = Queue()
p1 = Process(target=generate, args=(queue,))
p2 = Process(target=reader, args=(queue,))
p1.start()
p2.start()

  

Pipe方法:Pipe(管道)方法为两个进程提供了一种双向通信的机制,Piped()函数返回一对连接对象,每个对象表示管道的一端。每个连接对象都有send()和recv()方法

from multiprocessing import Pipe, Process
import random def generate(pipe):
while True:
value = random.randrange(10)
pipe.send(value)
print("Value sent: %s" % (value)) def reader(pipe):
f = open("output.txt", "w")
while True:
value = pipe.recv()
f.write(str(value))
print(".") input_p, output_p = Pipe()
p1 = Process(target=generate, args=(input_p,))
p2 = Process(target=reader, args=(output_p,))
p1.start()
p2.start()

  

多进程也有事件Event,它们的工作方式与多线程类似,只是有一点需要记住,事件对象不能被传递到子进程的函数中,这样做会导致运行时错误,信号机制只能在主进程中被子进程共享:

from multiprocessing import Pool, Event
import time event = Event()
event.set() def worker(i):
if event.is_set():
time.sleep(0.1)
print("A - %s" % (time.time()))
event.clear()
else:
time.sleep(0.1)
print("B - %s" % (time.time()))
event.set() pool = Pool(3)
pool.map(worker, range(9))

  

Python之多线程与多进程(二)的更多相关文章

  1. Python之多线程和多进程

    一.多线程 1.顺序执行单个线程,注意要顺序执行的话,需要用join. #coding=utf-8 from threading import Thread import time def my_co ...

  2. python的多线程和多进程(一)

    在进入主题之前,我们先学习一下并发和并行的概念: --并发:在操作系统中,并发是指一个时间段中有几个程序都处于启动到运行完毕之间,且这几个程序都是在同一个处理机上运行.但任一时刻点上只有一个程序在处理 ...

  3. Python的多线程和多进程

    (1)多线程的产生并不是因为发明了多核CPU甚至现在有多个CPU+多核的硬件,也不是因为多线程CPU运行效率比单线程高.单从CPU的运行效率上考虑,单任务进程及单线程效率是最高的,因为CPU没有任何进 ...

  4. Python【多线程与多进程】

    import time,threading print("=======串行方式.并行两种方式调用run()函数=======")def run(): print('哈哈哈') # ...

  5. python的多线程、多进程代码示例

    python多进程和多线程的区别:python的多线程不是真正意义上的多线程,由于python编译器的问题,导致python的多线程存在一个PIL锁,使得python的多线程的CPU利用率比预期的要低 ...

  6. selenium +python之多线程与多进程应用于自动化测试

    多线程与多进程与自动化测试用例结合起来执行,从而节省测试用例的总体运行时间. 多线程执行测试测试用例 以百度搜索为例,通过不同的浏览器来启动不同的线程. from selenium import we ...

  7. Python之多线程与多进程(一)

    多线程 多线程是程序在同样的上下文中同时运行多条线程的能力.这些线程共享同一个进程的资源,可以在并发模式(单核处理器)或并行模式(多核处理器)下执行多个任务 多线程有以下几个优点: 持续响应:在单线程 ...

  8. Python中多线程与多进程的恩恩怨怨

    概念: 并发:当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运 ...

  9. python的多线程、多进程、协程用代码详解

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:刘早起早起 PS:如有需要Python学习资料的小伙伴可以加点击下方链 ...

随机推荐

  1. java中接口(interface)和虚基类(abstract class)的区别

    在Java语言中,abstract class和interface是支持抽象类定义的两种机制.正是由于这两种机制的存在,才赋予了Java强大的面向对象能力.abstract class和interfa ...

  2. CSS grid layout demo 网格布局实例

    直接 上代码,里面我加注释,相当的简单, 也可以去我的github上直接下载代码,顺手给个星:https://github.com/yurizhang/micro-finance-admin-syst ...

  3. Jquery each跳出循环

    Jquery each跳出循环break--return false--跳出所有循环continue--return true--跳出当前循环

  4. iOS NSDecimalNumber 使用

    在iOS开发中,经常遇到和货币价格计算相关的,这时就需要注意计算精度的问题.使用float类型运算,经常出现误差.为了解决这种问题我们使用NSDecimalNumber,下面将通过例子的形式给大家展示 ...

  5. uvm_mem——寄存器模型(十二)

    看完了寄存器,再来看看存储器: //------------------------------------------------------------------------------ // ...

  6. 【装载】删除Oracle11G

    卸载Oracle步骤:1.停止所有与ORACLE相关的服务.2. 使用OUI(Oracle Universal Installer)卸载Oracle软件.   “开始”->“程序”->“O ...

  7. UVA 11214 Guarding the Chessboard 守卫棋盘(迭代加深+剪枝)

    暴力,和八皇后很像,用表示i+j和i-j标记主对角线,但是还是要加一些的剪枝的. 1.最裸的暴搜 6.420s,差点超时 2.之前位置放过的就没必要在放了,每次从上一次放的位置开始放 0.400s # ...

  8. 使用Timer组件制作左右飘动的窗体

    实现效果: 知识运用: Form类的Left和Top属性 实现代码: private void timer1_Tick(object sender, EventArgs e) { Rectangle ...

  9. 生成gt数据出问题

    使用cout打印uchar类型数据时,打印出来是其相应的ascii码

  10. 【转】Java8学习笔记(1) -- 从函数式接口说起

    http://blog.csdn.net/zxhoo/article/details/38349011 函数式接口 理解Functional Interface(函数式接口,以下简称FI)是学习Jav ...