场景
我最近用Python
的print
,通过打印一帧帧的进度条,实现了一个进度条样式,顺便跟大家分享一下代码:
import time
AT_PROGRESS_BAR = [
"( )",
"(@ )",
"(@@ )",
"(@@@ )",
"(@@@@ )",
"(@@@@@ )",
"(@@@@@@ )",
"(@@@@@@@ )",
"(@@@@@@@@ )",
"(@@@@@@@@@ )",
"(@@@@@@@@@@ )",
"(@@@@@@@@@@@ )",
"(@@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@)",
"( @@@@@@@@@@@)",
"( @@@@@@@@@@)",
"( @@@@@@@@@)",
"( @@@@@@@@)",
"( @@@@@@@)",
"( @@@@@@)",
"( @@@@@)",
"( @@@@)",
"( @@@)",
"( @@)",
"( @)",
"( )",
]
def print_progress_bar():
while True:
for i in AT_PROGRESS_BAR:
print(i, end="")
time.sleep(0.1)
print('\r' * len(i), end="")
运行效果如下:
然鹅,我现在有一个函数,叫做long_function()
,用来模拟一个执行时间很长的函数:
def long_function():
for i in range(20):
# 每隔一秒就 print 一下,以示函数正在执行。
time.sleep(1)
print("函数正在执行!")
我想让long_function()
执行的时候,让print_progress_bar()
也一块伴随执行。但是如果我们直接使用如下代码:
if __name__ == '__main__':
long_function()
print_progress_bar()
两个函数是不会同时执行的。因此,我们就需要使用multiprocessing
模块,使用并行程序1执行。
需求一:2进程并行执行
代码如下:
import time
from multiprocessing import Process
AT_PROGRESS_BAR = [
"( )",
"(@ )",
"(@@ )",
"(@@@ )",
"(@@@@ )",
"(@@@@@ )",
"(@@@@@@ )",
"(@@@@@@@ )",
"(@@@@@@@@ )",
"(@@@@@@@@@ )",
"(@@@@@@@@@@ )",
"(@@@@@@@@@@@ )",
"(@@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@ )",
"( @@@@@@@@@@@@)",
"( @@@@@@@@@@@)",
"( @@@@@@@@@@)",
"( @@@@@@@@@)",
"( @@@@@@@@)",
"( @@@@@@@)",
"( @@@@@@)",
"( @@@@@)",
"( @@@@)",
"( @@@)",
"( @@)",
"( @)",
"( )",
]
def print_progress_bar():
while True:
for i in AT_PROGRESS_BAR:
print(i, end="")
time.sleep(0.1)
print('\r' * len(i), end="")
def long_function():
for i in range(20):
# 每隔一秒就 print 一下,以示函数正在执行。
time.sleep(1)
print("函数正在执行!")
if __name__ == '__main__':
p = Process(target=print_progress_bar, args=())
p.start()
long_function()
p.join()
在上面的代码中,我们首先在__main__
(主程序)里面新建一个Process
实例;其次,用start()
启动这个程序;第三,运行父程序long_function()
,最后再用join()
函数等待到程序终止。
效果(因为两个print
语句冲突,所以可能打印的效果不太好,但是是正常的):
需求二:2+进程并行
对于2+进程的并行程序来说,我们使用进程池(Pool
)来实现会更方便一些。代码如下:
import time
from multiprocessing import Process, Pool # 引入 Pool
AT_PROGRESS_BAR = [...] # 为了观看方便,把这个数组省略了
def print_progress_bar():
while True:
for i in AT_PROGRESS_BAR:
print(i, end="")
time.sleep(0.1)
print('\r' * len(i), end="")
def long_function():
for i in range(20):
# 每隔一秒就 print 一下,以示函数正在执行。
time.sleep(1)
print("函数正在执行!")
# 我在这里新增了第三个函数:bfunc,作为第三个进程。
def bfunc():
for i in range(30):
time.sleep(0.5)
print("bfunc")
if __name__ == '__main__':
pool = Pool(2) # 新建一个含有两个进程的进程池
pool.apply_async(print_progress_bar, args=()) # 添加 print_progress_bar 进程
pool.apply_async(bfunc, args=()) # 添加 bfunc 进程
long_function() # 执行主进程
p.close() # 进程池不再接受新进程
p.start() # 启动进程池
p.join() # 进程池等待结束
三个进程并行的运行效果(print
语句还是有些冲突,不过运行正常):
注意
如果你把pool
里添加上4+个进程的话,程序的并行可能失败。这取决于你的电脑有几个 CPU(就是几核),可以通过如下os.cpu_count()
命令查询:
Python 3.8.2 (v3.8.2:7b3ab5921f, Feb 24 2020, 17:52:18)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>>
>>> os.cpu_count()
4
>>>
需求三:两进程并行中,其中一个进程停止,另外一个进程也停止
一开始我使用Pool
进行并行,并且尝试捕捉SIGCHLD
信号,来解决标题中的问题,但是这样好像行不太同。实际上我们可以使用两个Process
实现,代码如下:
import time
from multiprocessing import Process
AT_PROGRESS_BAR = [...] # 为了读者方便,省略数组内容
def print_progress_bar():
while True:
for i in AT_PROGRESS_BAR:
print(i, end="")
time.sleep(0.1)
print('\r' * len(i), end="")
def long_function():
for i in range(20):
# 每隔一秒就 print 一下,以示函数正在执行。
time.sleep(1)
print("函数正在执行!")
if __name__ == '__main__':
p = Process(target=long_function, args=())
p.start()
p2 = Process(target=print_progress_bar, args=())
p2.start()
p.join()
p2.terminate()
在上面的代码中,我们希望long_function()
执行结束后,停止print_progress_bar()
进程。
代码中:首先,我创建了p
和p2
两个Process
,分别代表long_function
和print_progress_bar
,再分别start()
进程;其次,我通过p.join()
等待p
进程结束,却不等待p2
结束;最后,我巧妙地在p
结束(即long_function()
结束后)后,通过terminate()
停止p2
进程。
这种方法的好处是,我们不用等待或传递任何信号,而只是通过代码的从上到下依次执行规律,解决标题中的问题。
END
https://docs.python.org/zh-cn/3.8/library/multiprocessing.html ↩︎