安装:
pip install multiprocess
使用:
import multiprocessing
创建进程:
multiprocessing.Process([group [, target [, name [, args [, kwargs]]]]])
# target表示调用对象
# args表示调用对象的位置参数元组
# kwargs表示调用对象的字典
# name为别名
# group实质上不使用
方法:
is_alive() :进程是否存活
join([timeout]):主进程阻塞,等待子进程的退出,join方法要在close或terminate之后使用
run():进程调用start时自动调用run
start() :启动一个进程
属性:authkey、daemon(要通过start()设置),exitcode(进程在运行时为None、如果为–N,表示被信号N结束)、name、pid。其中daemon是父进程终止后自动终止,且自己不能产生新进程,必须在start()之前设置。
创建一个单进程:
import multiprocessing
import time
def func():
for i in range(5):
print(i,"*"*10)
time.sleep(2)
if __name__ == '__main__':
p=multiprocessing.Process(target=func)
p.start()
print("p.pid:",p.pid)
print("p.name",p.name)
print("p.is_alive",p.is_alive())
# p.pid: 11792
# p.name Process-1
# p.is_alive True
# 0 **********
# 1 **********
# 2 **********
# 3 **********
# 4 **********
2.创建函数并将其作为多进程
import multiprocessing
import time
def func1():
for i in range(5):
print(i,"*"*10)
time.sleep(2)
def func2():
for i in range(5):
print(i*10,"*"*10)
time.sleep(2)
if __name__ == '__main__':
p1=multiprocessing.Process(target=func1)
p1.start()
p2 = multiprocessing.Process(target=func2)
p2.start()
print("The number of CPU is:" + str(multiprocessing.cpu_count()))
# The number of CPU is:2
# 0 **********
# 0 **********
# 1 **********
# 10 **********
# 2 **********
# 20 **********
# 3 **********
# 30 **********
# 4 **********
# 40 **********
将进程定义为类
import multiprocessing
import time
class Mytest(multiprocessing.Process):
def __init__(self,interval):
multiprocessing.Process.__init__(self)
self.interval=interval
def run(self):
n = 5
while n > 0:
print("the time is {0}".format(time.ctime()))
time.sleep(self.interval)
n -= 1
if __name__ == '__main__':
p=Mytest(2)
p.start()
# the time is Tue Apr 27 20:31:10 2021
# the time is Tue Apr 27 20:31:12 2021
# the time is Tue Apr 27 20:31:14 2021
# the time is Tue Apr 27 20:31:16 2021
# the time is Tue Apr 27 20:31:18 2021
守护进程(Daemon Process)
守护进程是在后台运行的进程,它通常不受用户直接控制,而是被设计为在系统启动时自动启动并在系统关闭时自动关闭。它们通常用于执行系统服务、后台任务、服务器等,不需要与用户交互。
守护进程的特点包括:
当父进程(通常是主程序)结束时,它们不会继续运行。
它们通常没有控制终端。
它们通常不会产生控制台输出,而是将日志写入文件或其他适当的位置。
它们不会阻止系统的正常关机。
daemon属性
在Python的multiprocessing模块中,可以使用Process类创建进程,并且每个Process对象都有一个daemon属性,默认情况下,它的值是False,即进程是非守护进程。
daemon=False:如果将进程的daemon属性设置为False,则该进程是非守护进程。在这种情况下,当主程序(父进程)结束时,该进程不会随之结束,而会继续运行。
daemon=True:如果将进程的daemon属性设置为True,则该进程是守护进程。在这种情况下,当主程序(父进程)结束时,它会随之结束。
from multiprocessing import Process
import time
def daemon_function():
while True:
print("Daemon Process is running...")
time.sleep(1)
if __name__ == "__main__":
daemon_process = Process(target=daemon_function)
daemon_process.daemon = True # 设置为守护进程
daemon_process.start()
# 主程序
print("Main Program is running...")
time.sleep(3)
print("Main Program is done.")
在这个示例中,daemon_function函数创建了一个死循环,当daemon_process进程被设置为守护进程时,它会在主程序结束后立即终止,而不管它是否完成。
使用场景
当你希望在主程序结束时自动终止某些工作线程或任务时,可以将它们设置为守护进程。
如果你希望一个长期运行的任务在主程序结束后继续运行,那么将其设置为非守护进程。
注意:在多进程编程中,如果主程序退出,守护进程通常会被强制终止,因此要小心确保守护进程没有执行必须要完成的工作
不加daemon:
import multiprocessing
import time
def func(sle):
print("time now_1:{}".format(time.ctime()))
time.sleep(sle)
print("time now_2:{}".format(time.ctime()))
if __name__ == '__main__':
p=multiprocessing.Process(target=func,args=(2,))
p.start()
print("end!")
# end!
# time now_1:Tue May 18 16:52:22 2021
# time now_2:Tue May 18 16:52:24 2021
加上daemon:
import multiprocessing
import time
def func(sle):
print("time now_1:{}".format(time.ctime()))
time.sleep(sle)
print("time now_2:{}".format(time.ctime()))
if __name__ == '__main__':
p=multiprocessing.Process(target=func,args=(2,))
p.daemon=True
p.start()
print("end!")
# end!
进程池
进程池是多进程编程中的一种重要概念,它允许你有效地管理和重用多个子进程,以执行并行的任务。Python中的multiprocessing模块提供了进程池的支持,通过使用进程池,你可以更轻松地处理并行任务,尤其是在需要多次创建和销毁进程的情况下。
创建进程池
在Python中,你可以使用multiprocessing.Pool类来创建进程池。通常,你可以指定进程池中的进程数量。例如:
from multiprocessing import Pool
pool = Pool(processes=4) # 创建包含4个进程的进程池
这将创建一个具有4个工作进程的进程池,可以并行执行多个任务。
提交任务
一旦有了进程池,你可以使用pool.map()或pool.apply_async()等方法来提交任务给进程池中的进程。
pool.map():将任务分发给进程池中的工作进程,并等待它们完成,然后返回结果。
results = pool.map(worker_function, some_data)
pool.apply_async():非阻塞地提交一个任务,返回一个AsyncResult对象,可以稍后用来获取结果。
result = pool.apply_async(worker_function, (arg,))
获取结果
对于使用pool.map()的任务,结果会在所有任务完成后返回,而对于使用pool.apply_async()的任务,你需要使用get()方法来获取结果。
result = pool.apply_async(worker_function, (arg,))
result_value = result.get() # 阻塞等待任务完成并获取结果
关闭和终止进程池
在使用完进程池后,你需要显式地关闭和终止它,以确保资源得到释放。
pool.close():关闭进程池,不再接受新任务。
pool.join():等待所有任务完成,然后关闭进程池。
pool.terminate():立即终止所有工作进程,不等待它们完成。
进程池的应用
进程池适用于各种需要并行处理的任务,例如批量处理数据、爬虫、图像处理、计算密集型操作等。通过合理地设置进程池大小,可以充分利用多核处理器的性能。以下是一个示例,演示如何使用进程池来并行计算一组数据的平方:
from multiprocessing import Pool
def square(n):
return n * n
if __name__ == "__main__":
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
pool = Pool(processes=4)
results = pool.map(square, data)
pool.close()
pool.join()
print(results)
在这个示例中,我们创建了一个包含4个进程的进程池,然后使用pool.map()并行计算输入数据的平方,最后获取结果并打印。
join
join让其中一个子进程运行,在这个子进程运行完毕,在让另外一个子进程运行,所以在其中一个子进程运行期间,其他进程只能按着固有的顺序等待。具体来说,join() 方法会阻塞当前进程,直到被调用的进程(通常是子进程)完成其执行。这对于确保子进程的工作已经完成并且获取其结果非常有用。
基本用法
join() 方法通常被调用在创建并启动一个子进程后,以等待该子进程的完成。例如:
from multiprocessing import Process
def worker_function():
# 这是子进程执行的代码
pass
process = Process(target=worker_function)
process.start() # 启动子进程
process.join() # 阻塞当前进程,等待子进程完成
在上述示例中,join() 方法会阻塞主进程(或当前进程),直到子进程执行完毕。
超时参数
join() 方法还可以接受一个可选的超时参数,指定最长等待时间(以秒为单位)。如果子进程在超时时间内未完成,join() 方法将不再等待,而是继续执行当前进程。这可以用于避免主进程永久阻塞。
process.join(timeout=10) # 最多等待10秒
多个进程的等待
如果你有多个子进程需要等待完成,可以在每个子进程上调用join() 方法:
process1 = Process(target=worker_function1)
process2 = Process(target=worker_function2)
process1.start()
process2.start()
process1.join()
process2.join()
这样,主进程会等待process1 和 process2 都完成后才继续执行。
在进程池中的应用
在使用进程池时,通常会在提交任务后使用join() 方法等待所有任务的完成:
from multiprocessing import Pool
def worker_function(arg):
# 进程池中每个进程执行的函数
pass
pool = Pool(processes=4) # 创建包含4个进程的进程池
results = pool.map(worker_function, some_data) # 提交任务给进程池
pool.close() # 关闭进程池,不再接受新任务
pool.join() # 等待所有任务完成
这里,join() 方法用于等待所有提交给进程池的任务完成。
互斥锁
要实现多进程之间的互斥锁,通常会使用multiprocessing模块中的Lock对象。Lock对象允许你创建一个互斥锁,以确保在多个进程中只有一个进程可以访问共享资源,防止竞争条件和数据不一致性。
以下是如何在Python中实现多进程互斥锁的详细步骤:
首先,导入multiprocessing模块,并创建一个Lock对象。
在你的多进程函数中,首先尝试获取锁,如果获取成功,表示没有其他进程正在使用共享资源,然后执行需要互斥访问的代码块。
在使用完共享资源后,释放锁,以允许其他进程访问。
import multiprocessing
# 共享资源,可以是一个列表、字典或任何需要互斥访问的对象
shared_resource = []
# 创建一个Lock对象
lock = multiprocessing.Lock()
def worker_function(item):
global shared_resource
# 尝试获取锁
lock.acquire()
try:
# 在获取了锁之后,可以安全地修改共享资源
shared_resource.append(item)
print(f"Added {item} to shared resource by process {multiprocessing.current_process().name}")
finally:
# 无论如何,都要释放锁,以确保其他进程可以访问
lock.release()
if __name__ == "__main__":
# 创建多个进程来模拟对共享资源的访问
processes = []
for i in range(5):
p = multiprocessing.Process(target=worker_function, args=(i,))
processes.append(p)
p.start()
for p in processes:
p.join()
print("Final shared resource:", shared_resource)
在这个示例中,我们创建了一个shared_resource列表作为共享资源,并使用lock对象来确保多个进程安全地修改它。每个进程都会尝试获取锁,如果成功,就会将一个项目添加到共享资源中,然后释放锁,以允许其他进程执行相同的操作。
需要注意的是,获取和释放锁是成对的操作,确保无论如何锁都会被释放,以避免死锁情况。