资深程序员带你学Python!深入 Python 多进程编程基础!

<p style="margin:10px auto;color:rgb(57,57,57);font-family:verdana,'ms song',Arial,Helvetica,sans-serif;font-size:14px;text-align:left;background-color:rgb(250,247,239);">多进程编程知识是Python程序员进阶高级的必备知识点,我们平时习惯了使用multiprocessing库来操纵多进程,但是并不知道它的具体实现原理。下面我对多进程的常用知识点都简单列了一遍,使用原生的多进程方法调用,帮助读者理解多进程的实现机制。代码跑在linux环境下。没有linux条件的,可以使用docker或者虚拟机运行进行体验。

<pre class="prettyprint hljs Nginx" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,57);font-size:14px;text-align:left;background-color:rgb(250,239);"><span class="hljs-attribute" style="margin:0px;padding:0px;color:rgb(163,21,21);">docker pull python:<span class="hljs-number" style="margin:0px;padding:0px;">2.<span class="hljs-number" style="margin:0px;padding:0px;">7
<h2 style="margin-top:10px;margin-bottom:10px;padding:0px;font-size:21px;line-height:1.5;color:rgb(57,sans-serif;text-align:left;background-color:rgb(250,239);">生成子进程<p style="margin:10px auto;color:rgb(57,239);">Python生成子进程使用 <code style="margin:0px;padding:0px;">os.fork() ,它将产生一个子进程。fork调用同时在父进程和主进程同时返回,在父进程中返回子进程的pid,在子进程中返回0,如果返回值小于零,说明子进程产生失败,一般是因为操作系统资源不足。

<code class="language-python"><span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">import os
def create_child():
pid = os.fork()
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">if pid > <span class="hljs-number" style="margin:0px;padding:0px;">0:
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">print <span class="hljs-string" style="margin:0px;padding:0px;color:rgb(163,21);">'in father process'
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">return <span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">True
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">elif pid == <span class="hljs-number" style="margin:0px;padding:0px;">0:
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,21);">'in child process'
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">False
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">else:
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">raise
<h2 style="margin-top:10px;margin-bottom:10px;padding:0px;font-size:21px;line-height:1.5;color:rgb(57,239);">生成多个子进程<p style="margin:10px auto;color:rgb(57,239);">我们调用 <code style="margin:0px;padding:0px;">create_child 方法多次就可以生成多个子进程,前提是必须保证 <code style="margin:0px;padding:0px;">create_child 是在父进程里执行,如果是子进程,就不要在调用了。

<pre class="prettyprint hljs lua" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,239);"># coding: utf<span class="hljs-number" style="margin:0px;padding:0px;">-8
# child.py
import os

def create_child(i):
pid = <span class="hljs-built_in" style="margin:0px;padding:0px;color:rgb(0,255);">os.fork()
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">if pid > <span class="hljs-number" style="margin:0px;padding:0px;">0:
<span class="hljs-built_in" style="margin:0px;padding:0px;color:rgb(0,255);">return pid
elif pid == <span class="hljs-number" style="margin:0px;padding:0px;">0:
<span class="hljs-built_in" style="margin:0px;padding:0px;color:rgb(0,21);">'in child process',i
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">return <span class="hljs-number" style="margin:0px;padding:0px;">0
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">else:
raise

for i <span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">in range(<span class="hljs-number" style="margin:0px;padding:0px;">10): # 循环<span class="hljs-number" style="margin:0px;padding:0px;">10次,创建<span class="hljs-number" style="margin:0px;padding:0px;">10个子进程
pid = create_child(i)
# pid==<span class="hljs-number" style="margin:0px;padding:0px;">0是子进程,应该立即退出循环,否则子进程也会继续生成子进程
# 子子孙孙,那就生成太多进程了
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">if pid == <span class="hljs-number" style="margin:0px;padding:0px;">0:
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">break
<p style="margin:10px auto;color:rgb(57,239);">运行 <code style="margin:0px;padding:0px;">python child.py ,输出

<pre class="prettyprint hljs powershell" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,239);"><span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">in father process
in father process
in child <span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">process <span class="hljs-number" style="margin:0px;padding:0px;">0
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">in child <span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">process <span class="hljs-number" style="margin:0px;padding:0px;">1
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">in father process
in child <span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">process <span class="hljs-number" style="margin:0px;padding:0px;">2
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">process <span class="hljs-number" style="margin:0px;padding:0px;">3
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">process <span class="hljs-number" style="margin:0px;padding:0px;">4
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">process <span class="hljs-number" style="margin:0px;padding:0px;">5
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">process <span class="hljs-number" style="margin:0px;padding:0px;">6
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">process <span class="hljs-number" style="margin:0px;padding:0px;">7
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">process <span class="hljs-number" style="margin:0px;padding:0px;">8
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">process <span class="hljs-number" style="margin:0px;padding:0px;">9
<h2 style="margin-top:10px;margin-bottom:10px;padding:0px;font-size:21px;line-height:1.5;color:rgb(57,239);">进程休眠<p style="margin:10px auto;color:rgb(57,239);">使用time.sleep可以使进程休眠任意时间,单位为秒,可以是小数

<pre class="prettyprint hljs go" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,255);">import time
for i in <span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">range(<span class="hljs-number" style="margin:0px;padding:0px;">5):
<span class="hljs-built_in" style="margin:0px;padding:0px;color:rgb(0,21);">'hello'
time.sleep(<span class="hljs-number" style="margin:0px;padding:0px;">1) # 睡<span class="hljs-number" style="margin:0px;padding:0px;">1s
<h2 style="margin-top:10px;margin-bottom:10px;padding:0px;font-size:21px;line-height:1.5;color:rgb(57,239);">杀死子进程<p style="margin:10px auto;color:rgb(57,239);">使用os.kill(pid,sig_num)可以向进程号为pid的子进程发送信号,sig_num常用的有SIGKILL(暴力杀死,相当于kill -9),SIGTERM(通知对方退出,相当于kill不带参数),SIGINT(相当于键盘的ctrl+c)。

<pre class="prettyprint hljs vim" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,239);"># codin<span class="hljs-variable" style="margin:0px;padding:0px;color:#008000;">g: utf-<span class="hljs-number" style="margin:0px;padding:0px;">8
# kill.py

import os
import time
import signal


def create_child():
pid = os.fork()
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">return pid
elif pid == <span class="hljs-number" style="margin:0px;padding:0px;">0:
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">else:
raise


pid = create_child()
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">while True: # 子进程死循环打印字符串
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,21);">'in child process'
time.<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">sleep(<span class="hljs-number" style="margin:0px;padding:0px;">1)
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,21);">'in father process'
time.<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">sleep(<span class="hljs-number" style="margin:0px;padding:0px;">5) # 父进程休眠<span class="hljs-number" style="margin:0px;padding:0px;">5s再杀死子进程
os.kill(pid,signal.SIGKILL)
time.<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">sleep(<span class="hljs-number" style="margin:0px;padding:0px;">5) # 父进程继续休眠<span class="hljs-number" style="margin:0px;padding:0px;">5s观察子进程是否还有输出
<p style="margin:10px auto;color:rgb(57,239);">运行 <code style="margin:0px;padding:0px;">python kill.py ,我们看到控制台输出如下

<pre class="prettyprint hljs go" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,239);">in father process
in child process
# 等<span class="hljs-number" style="margin:0px;padding:0px;">1s
in child process
# 等<span class="hljs-number" style="margin:0px;padding:0px;">1s
in child process
# 等<span class="hljs-number" style="margin:0px;padding:0px;">1s
in child process
# 等<span class="hljs-number" style="margin:0px;padding:0px;">1s
in child process
# 等了<span class="hljs-number" style="margin:0px;padding:0px;">5s
<p style="margin:10px auto;color:rgb(57,239);">说明os.kill执行之后,子进程已经停止输出

<h2 style="margin-top:10px;margin-bottom:10px;padding:0px;font-size:21px;line-height:1.5;color:rgb(57,239);">僵尸子进程<p style="margin:10px auto;color:rgb(57,239);">在上面的例子中,os.kill执行完之后,我们通过ps -ef|grep python快速观察进程的状态,可以发现子进程有一个奇怪的显示 <code style="margin:0px;padding:0px;">

<pre class="prettyprint hljs vim" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,239);">root <span class="hljs-number" style="margin:0px;padding:0px;">12 <span class="hljs-number" style="margin:0px;padding:0px;">1 <span class="hljs-number" style="margin:0px;padding:0px;">0 <span class="hljs-number" style="margin:0px;padding:0px;">11:<span class="hljs-number" style="margin:0px;padding:0px;">22 <span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">pts/<span class="hljs-number" style="margin:0px;padding:0px;">0 <span class="hljs-number" style="margin:0px;padding:0px;">00:<span class="hljs-number" style="margin:0px;padding:0px;">00:<span class="hljs-number" style="margin:0px;padding:0px;">00 <span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">python kill.py
root <span class="hljs-number" style="margin:0px;padding:0px;">13 <span class="hljs-number" style="margin:0px;padding:0px;">12 <span class="hljs-number" style="margin:0px;padding:0px;">0 <span class="hljs-number" style="margin:0px;padding:0px;">11:<span class="hljs-number" style="margin:0px;padding:0px;">22 <span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">pts/<span class="hljs-number" style="margin:0px;padding:0px;">0 <span class="hljs-number" style="margin:0px;padding:0px;">00:<span class="hljs-number" style="margin:0px;padding:0px;">00:<span class="hljs-number" style="margin:0px;padding:0px;">00 [<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">python] <span class="hljs-symbol" style="margin:0px;padding:0px;color:rgb(0,176,232);"><<span class="hljs-symbol" style="margin:0px;padding:0px;color:rgb(0,232);">defunct<span class="hljs-symbol" style="margin:0px;padding:0px;color:rgb(0,232);">>
<p style="margin:10px auto;color:rgb(57,239);">待父进程终止后,子进程也一块消失了。那 <code style="margin:0px;padding:0px;"> 是什么含义呢?

<p style="margin:10px auto;color:rgb(57,239);">它的含义是「僵尸进程」。子进程结束后,会立即成为僵尸进程,僵尸进程占用的操作系统资源并不会立即释放,它就像一具尸体啥事也不干,但是还是持续占据着操作系统的资源(内存等)。

<h2 style="margin-top:10px;margin-bottom:10px;padding:0px;font-size:21px;line-height:1.5;color:rgb(57,239);">收割子进程<p style="margin:10px auto;color:rgb(57,239);">如果彻底干掉僵尸进程?父进程需要调用waitpid(pid,options)函数,「收割」子进程,这样子进程才可以灰飞烟灭。waitpid函数会返回子进程的退出状态,它就像子进程留下的临终遗言,必须等父进程听到后才能彻底瞑目。

<pre class="prettyprint hljs vim" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,239);"># codin<span class="hljs-variable" style="margin:0px;padding:0px;color:#008000;">g: utf-<span class="hljs-number" style="margin:0px;padding:0px;">8
import os
import time
import signal
def create_child():
pid = os.fork()
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">else:
raise
pid = create_child()
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,signal.SIGTERM)
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">ret = os.waitpid(pid,<span class="hljs-number" style="margin:0px;padding:0px;">0) # 收割子进程
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">print <span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">ret # 看看到底返回了什么
time.<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">sleep(<span class="hljs-number" style="margin:0px;padding:0px;">5) # 父进程继续休眠<span class="hljs-number" style="margin:0px;padding:0px;">5s观察子进程是否还存在
<p style="margin:10px auto;color:rgb(57,239);">运行python kill.py输出如下

<pre class="prettyprint hljs powershell" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,255);">in father process
in child process
in child process
in child process
in child process
in child process
in child <span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">process
(<span class="hljs-number" style="margin:0px;padding:0px;">125,<span class="hljs-number" style="margin:0px;padding:0px;">9)
<p style="margin:10px auto;color:rgb(57,239);">我们看到waitpid返回了一个tuple,第一个是子进程的pid,第二个9是什么含义呢,它在不同的操作系统上含义不尽相同,不过在Unix上,它通常的value是一个16位的整数值,前8位表示进程的退出状态,后8位表示导致进程退出的信号的整数值。所以本例中退出状态位0,信号编号位9,还记得 <code style="margin:0px;padding:0px;">kill -9 这个命令么,就是这个9表示暴力杀死进程。

<p style="margin:10px auto;color:rgb(57,239);">如果我们将os.kill换一个信号才看结果,比如换成os.kill(pid,signal.SIGTERM),可以看到返回结果变成了 <code style="margin:0px;padding:0px;">(138,15) ,15就是SIGTERM信号的整数值。

<p style="margin:10px auto;color:rgb(57,239);"><code style="margin:0px;padding:0px;">waitpid(pid,0) 还可以起到等待子进程结束的功能,如果子进程不结束,那么该调用会一直卡住。

<h2 style="margin-top:10px;margin-bottom:10px;padding:0px;font-size:21px;line-height:1.5;color:rgb(57,239);">捕获信号<p style="margin:10px auto;color:rgb(57,239);">SIGTERM信号认处理动作就是退出进程,其实我们还可以设置SIGTERM信号的处理函数,使得它不退出

<pre class="prettyprint hljs vim" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,255);">if pid == <span class="hljs-number" style="margin:0px;padding:0px;">0:
signal.signal(signal.SIGTERM,signal.SIG_IGN)
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,signal.SIGTERM) # 发一个SIGTERM信号
time.<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">sleep(<span class="hljs-number" style="margin:0px;padding:0px;">5) # 父进程继续休眠<span class="hljs-number" style="margin:0px;padding:0px;">5s观察子进程是否还存在
os.kill(pid,signal.SIGKILL) # 发一个SIGKILL信号
time.<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">sleep(<span class="hljs-number" style="margin:0px;padding:0px;">5) # 父进程继续休眠<span class="hljs-number" style="margin:0px;padding:0px;">5s观察子进程是否还存在
<p style="margin:10px auto;color:rgb(57,239);">我们在子进程里设置了信号处理函数,SIG_IGN表示忽略信号。我们发现第一次调用os.kill之后,子进程会继续输出。说明子进程没有被杀死。第二次os.kill之后,子进程终于停止了输出

<p style="margin:10px auto;color:rgb(57,239);">接下来我们换一个自定义信号处理函数,子进程收到SIGTERM之后,打印一句话再退出

<pre class="prettyprint hljs vim" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,239);"># codin<span class="hljs-variable" style="margin:0px;padding:0px;color:#008000;">g: utf-<span class="hljs-number" style="margin:0px;padding:0px;">8
import os
import sys
import time
import signal
def create_child():
pid = os.fork()
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">else:
raise
def i_will_die(sig_num,frame): # 自定义信号处理函数
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,21);">"child will die"
sys.<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">exit(<span class="hljs-number" style="margin:0px;padding:0px;">0)
pid = create_child()
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,i_will_die)
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,signal.SIGTERM)
time.<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,239);">输出如下

<pre class="prettyprint hljs lua" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,255);">in father process
in child process
in child process
in child process
in child process
in child process
child will die
<p style="margin:10px auto;color:rgb(57,239);">信号处理函数有两个参数,第一个sig_num表示被捕获信号的整数值,第二个frame不太好理解,一般也很少用。它表示被信号打断时,Python的运行的栈帧对象信息。读者可以不必深度理解。

<h2 style="margin-top:10px;margin-bottom:10px;padding:0px;font-size:21px;line-height:1.5;color:rgb(57,239);">多进程并行计算实例<p style="margin:10px auto;color:rgb(57,239);">下面我们使用多进程进行一个计算圆周率PI。对于圆周率PI有一个数学极限公式,我们将使用该公司来计算圆周率PI。

<p style="margin:10px auto;color:rgb(57,239);">

<p style="margin:10px auto;color:rgb(57,239);">先使用单进程版本

<pre class="prettyprint hljs elm" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,255);">import math
def pi(n):
s = 0.0
for i in range(n):
s += 1.0/(2i+1)/(2i+1)
return math.sqrt(8 s)
print pi(10000000)
<p style="margin:10px auto;color:rgb(57,239);">输出

<code class="language-css">3<span class="hljs-selector-class" style="margin:0px;padding:0px;">.14159262176
<p style="margin:10px auto;color:rgb(57,239);">这个程序跑了有一小会才出结果,不过这个值已经非常接近圆周率了。

<p style="margin:10px auto;color:rgb(57,239);">接下来我们用多进程版本,我们用redis进行进程间通信。

<pre class="prettyprint hljs vim" style="margin-bottom:0px;padding:0px;white-space:pre-wrap;color:rgb(57,239);"># codin<span class="hljs-variable" style="margin:0px;padding:0px;color:#008000;">g: utf-<span class="hljs-number" style="margin:0px;padding:0px;">8
import os
import sys
import math
import redis
def slice(mink,maxk):
s = <span class="hljs-number" style="margin:0px;padding:0px;">0.0
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">for <span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">k in <span class="hljs-built_in" style="margin:0px;padding:0px;color:rgb(0,255);">range(mink,maxk):
s += <span class="hljs-number" style="margin:0px;padding:0px;">1.0/(<span class="hljs-number" style="margin:0px;padding:0px;">2
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">k+<span class="hljs-number" style="margin:0px;padding:0px;">1)/(<span class="hljs-number" style="margin:0px;padding:0px;">2<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">k+<span class="hljs-number" style="margin:0px;padding:0px;">1)
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">return s
def pi(n):
pids = []
unit = n / <span class="hljs-number" style="margin:0px;padding:0px;">10
client = redis.StrictRedis()
client.<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">delete(<span class="hljs-string" style="margin:0px;padding:0px;color:rgb(163,21);">"result") # 保证结果集是干净的
del client # 关闭连接
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">for i in <span class="hljs-built_in" style="margin:0px;padding:0px;color:rgb(0,255);">range(<span class="hljs-number" style="margin:0px;padding:0px;">10): # 分<span class="hljs-number" style="margin:0px;padding:0px;">10个子进程
mink = unit
i
maxk = mink + unit
pid = os.fork()
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">if pid > <span class="hljs-number" style="margin:0px;padding:0px;">0:
pids.<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">append(pid)
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">else:
s = slice(mink,maxk) # 子进程开始计算
client = redis.StrictRedis()
client.rpush(<span class="hljs-string" style="margin:0px;padding:0px;color:rgb(163,21);">"result",str(s)) # 传递子进程结果
sys.<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">exit(<span class="hljs-number" style="margin:0px;padding:0px;">0) # 子进程结束
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">for pid in pid<span class="hljs-variable" style="margin:0px;padding:0px;color:#008000;">s:
os.waitpid(pid,<span class="hljs-number" style="margin:0px;padding:0px;">0) # 等待子进程结束
sum = <span class="hljs-number" style="margin:0px;padding:0px;">0
client = redis.StrictRedis()
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">for s in client.lrange(<span class="hljs-string" style="margin:0px;padding:0px;color:rgb(163,<span class="hljs-number" style="margin:0px;padding:0px;">0,-<span class="hljs-number" style="margin:0px;padding:0px;">1):
sum += float(s) # 收集子进程计算结果
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">return math.<span class="hljs-built_in" style="margin:0px;padding:0px;color:rgb(0,255);">sqrt(sum * <span class="hljs-number" style="margin:0px;padding:0px;">8)
<span class="hljs-keyword" style="margin:0px;padding:0px;color:rgb(0,255);">print pi(<span class="hljs-number" style="margin:0px;padding:0px;">10000000)
<p style="margin:10px auto;color:rgb(57,239);">我们将级数之和的计算拆分成10个子进程计算,每个子进程负责1/10的计算量,并将计算的中间结果扔到redis的队列中,然后父进程等待所有子进程结束,再将队列中的数据全部汇总起来计算最终结果。

<p style="margin:10px auto;color:rgb(57,239);">输出如下

<code class="language-css">3<span class="hljs-selector-class" style="margin:0px;padding:0px;">.14159262176
<p style="margin:10px auto;color:rgb(57,239);">这个结果和单进程结果一致,但是花费的时间要缩短了不少。

<p style="margin:10px auto;color:rgb(57,239);">这里我们之所以使用redis作为进程间通信方式,是因为进程间通信是一个比较复杂的技术,我们需要单独一篇文章来仔细讲,各位读者请耐心听我下回分解,我们将会使用进程间通信技术来替换掉这里的redis

<p style="margin:10px auto;color:rgb(57,239);">欢迎关注我的博客或者微信公众号:Python学习交流

<p style="margin:10px auto;color:rgb(57,239);">换人加入我的千人交流学习群:125240963

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


我最近重新拾起了计算机视觉,借助Python的opencv还有face_recognition库写了个简单的图像识别demo,额外定制了一些内容,原本想打包成exe然后发给朋友,不过在这当中遇到了许多小问题,都解决了,记录一下踩过的坑。 1、Pyinstaller打包过程当中出现warning,跟d
说到Pooling,相信学习过CNN的朋友们都不会感到陌生。Pooling在中文当中的意思是“池化”,在神经网络当中非常常见,通常用的比较多的一种是Max Pooling,具体操作如下图: 结合图像理解,相信你也会大概明白其中的本意。不过Pooling并不是只可以选取2x2的窗口大小,即便是3x3,
记得大一学Python的时候,有一个题目是判断一个数是否是复数。当时觉得比较复杂不好写,就琢磨了一个偷懒的好办法,用异常处理的手段便可以大大程度帮助你简短代码(偷懒)。以下是判断整数和复数的两段小代码: 相信看到这里,你也有所顿悟,能拓展出更多有意思的方法~
文章目录 3 直方图Histogramplot1. 基本直方图的绘制 Basic histogram2. 数据分布与密度信息显示 Control rug and density on seaborn histogram3. 带箱形图的直方图 Histogram with a boxplot on t
文章目录 5 小提琴图Violinplot1. 基础小提琴图绘制 Basic violinplot2. 小提琴图样式自定义 Custom seaborn violinplot3. 小提琴图颜色自定义 Control color of seaborn violinplot4. 分组小提琴图 Group
文章目录 4 核密度图Densityplot1. 基础核密度图绘制 Basic density plot2. 核密度图的区间控制 Control bandwidth of density plot3. 多个变量的核密度图绘制 Density plot of several variables4. 边
首先 import tensorflow as tf tf.argmax(tenso,n)函数会返回tensor中参数指定的维度中的最大值的索引或者向量。当tensor为矩阵返回向量,tensor为向量返回索引号。其中n表示具体参数的维度。 以实际例子为说明: import tensorflow a
seaborn学习笔记章节 seaborn是一个基于matplotlib的Python数据可视化库。seaborn是matplotlib的高级封装,可以绘制有吸引力且信息丰富的统计图形。相对于matplotlib,seaborn语法更简洁,两者关系类似于numpy和pandas之间的关系,seabo
Python ConfigParser教程显示了如何使用ConfigParser在Python中使用配置文件。 文章目录 1 介绍1.1 Python ConfigParser读取文件1.2 Python ConfigParser中的节1.3 Python ConfigParser从字符串中读取数据
1. 处理Excel 电子表格笔记(第12章)(代码下载) 本文主要介绍openpyxl 的2.5.12版处理excel电子表格,原书是2.1.4 版,OpenPyXL 团队会经常发布新版本。不过不用担心,新版本应该在相当长的时间内向后兼容。如果你有新版本,想看看它提供了什么新功能,可以查看Open
1. 发送电子邮件和短信笔记(第16章)(代码下载) 1.1 发送电子邮件 简单邮件传输协议(SMTP)是用于发送电子邮件的协议。SMTP 规定电子邮件应该如何格式化、加密、在邮件服务器之间传递,以及在你点击发送后,计算机要处理的所有其他细节。。但是,你并不需要知道这些技术细节,因为Python 的
文章目录 12 绘图实例(4) Drawing example(4)1. Scatterplot with varying point sizes and hues(relplot)2. Scatterplot with categorical variables(swarmplot)3. Scat
文章目录 10 绘图实例(2) Drawing example(2)1. Grouped violinplots with split violins(violinplot)2. Annotated heatmaps(heatmap)3. Hexbin plot with marginal dist
文章目录 9 绘图实例(1) Drawing example(1)1. Anscombe’s quartet(lmplot)2. Color palette choices(barplot)3. Different cubehelix palettes(kdeplot)4. Distribution
Python装饰器教程展示了如何在Python中使用装饰器基本功能。 文章目录 1 使用教程1.1 Python装饰器简单示例1.2 带@符号的Python装饰器1.3 用参数修饰函数1.4 Python装饰器修改数据1.5 Python多层装饰器1.6 Python装饰器计时示例 2 参考 1 使
1. 用GUI 自动化控制键盘和鼠标第18章 (代码下载) pyautogui模块可以向Windows、OS X 和Linux 发送虚拟按键和鼠标点击。根据使用的操作系统,在安装pyautogui之前,可能需要安装一些其他模块。 Windows: 不需要安装其他模块。OS X: sudo pip3
文章目录 生成文件目录结构多图合并找出文件夹中相似图像 生成文件目录结构 生成文件夹或文件的目录结构,并保存结果。可选是否滤除目录,特定文件以及可以设定最大查找文件结构深度。效果如下: root:[z:/] |--a.py |--image | |--cat1.jpg | |--cat2.jpg |
文章目录 VENN DIAGRAM(维恩图)1. 具有2个分组的基本的维恩图 Venn diagram with 2 groups2. 具有3个组的基本维恩图 Venn diagram with 3 groups3. 自定义维恩图 Custom Venn diagram4. 精致的维恩图 Elabo
mxnet60分钟入门Gluon教程代码下载,适合做过深度学习的人使用。入门教程地址: https://beta.mxnet.io/guide/getting-started/crash-course/index.html mxnet安装方法:pip install mxnet 1 在mxnet中使
文章目录 1 安装2 快速入门2.1 基本用法2.2 输出图像格式2.3 图像style设置2.4 属性2.5 子图和聚类 3 实例4 如何进一步使用python graphviz Graphviz是一款能够自动排版的流程图绘图软件。python graphviz则是graphviz的python实