Python 多进程

在本文中,我们将学习如何使用 Python 实现多进程。我们还讨论了它的高级概念。

什么是多进程?

多进程是系统并行运行一个或多个进程的能力。简单来说,多进程使用单个计算机系统内的两个或更多 CPU 。该方法还能够在多个进程之间分配任务。

处理单元共享主存储器和外围设备来同时处理程序。多进程应用分成更小的部分,独立运行。操作系统将每个进程分配给处理器。

Python 提供了支持交换进程的称为多进程的内置包。在使用多进程之前,我们必须了解进程对象。

为什么是多进程?

多进程对于在计算机系统中执行多种任务是必不可少的。假设一台计算机没有多进程器或单处理器。我们同时为该系统分配不同的进程。

然后,它将不得不中断前一个任务,并转移到另一个任务,以保持所有进程的运行。这就像厨师独自在厨房工作一样简单。他要做几个任务来烹饪食物,比如切、清洗、烹饪、揉面、烘焙等。

因此,多进程对于同时执行几个任务而不中断是必不可少的。它还使得跟踪所有任务变得容易。这就是为什么多进程的概念会出现。

  • 多进程可以表示为一台具有多个中央处理器的计算机。

  • 多核处理器是指具有两个或更多独立单元的单个计算组件。

在多进程中, CPU 可以一次分配多个任务,每个任务都有自己的处理器。

Python 中的多进程

Python 提供了multiprocessing模块来在单个系统中执行多个任务。它提供了一个用户友好和直观的 API 来处理多进程。

让我们理解多进程的简单例子。

示例-


from multiprocessing import Process
def disp():
print ('Hello !! Welcome to Python Tutorial')
if __name__ == '__main__':
p = Process(target=disp)
p.start()
p.join()

输出:

'Hello !! Welcome to Python Tutorial'

说明:

在上面的代码中,我们已经导入了 Process 类,然后在 disp() 函数中创建了 Process 对象。然后我们使用 start() 方法开始流程,并使用 join() 方法完成流程。我们也可以使用参数关键字在声明的函数中传递参数。

让我们理解下面这个带参数的多进程的例子。

示例- 2


# Python multiprocessing example
# importing the multiprocessing module

import multiprocessing
def cube(n):
# This function will print the cube of the given number
print("The Cube is: {}".format(n * n * n))

def square(n):
# This function will print the square of the given number
print("The Square is: {}".format(n * n))

if __name__ == "__main__":
# creating two processes
process1 = multiprocessing.Process(target= square, args=(5, ))
process2 = multiprocessing.Process(target= cube, args=(5, ))

# Here we start the process 1
process1.start()
# Here we start process 2
process2.start()

# The join() method is used to wait for process 1 to complete
process1.join()
# It is used to wait for process 1 to complete
process2.join()

# Print if both processes are completed
print("Both processes are finished")

输出:

The Cube is: 125
The Square is: 25
Both processes are finished

解释-

在上面的例子中,我们创建了两个函数-**cube()**函数计算给定数字的立方, square() 函数计算给定数字的平方。

接下来,我们定义了 process 类的 Process 对象,它有两个参数。第一个参数是代表要执行的函数的目标,第二个参数是代表要在函数中传递的参数的参数。


process1 = multiprocessing.Process(target= square, args=(5, ))
process2 = multiprocessing.Process(target= cube, args=(5, ))

我们使用了 start() 方法来启动流程。


process1.start()
process2.start()

正如我们在输出中看到的,它等待完成过程一,然后是过程二。最后一条语句在两个进程完成后执行。

Python 多进程类

Python multiprocessing模块提供了许多常用于构建并行程序的类。我们将讨论它的主要类——进程、队列和锁。我们已经在前面的例子中讨论了 Process 类。现在我们将讨论队列和锁类。

让我们看一个简单的例子,获取系统中当前的 CPU 数量。

示例-


import multiprocessing
print("The number of CPU currently working in system : ", multiprocessing.cpu_count())

输出:

('The number of CPU currently woking in system : ', 32)

以上 CPU 数量可能因您的电脑而异。对我们来说,核心数量是 32。

使用队列类的 Python 多进程

我们知道队列是数据结构的重要部分。Python 多进程与基于“先进先出”概念的数据结构队列完全相同。队列通常存储 Python 对象,并在进程间共享数据方面发挥重要作用。

队列作为参数在进程的目标函数中传递,以允许进程使用数据。队列提供 put() 函数插入数据, get() 函数从队列中获取数据。让我们理解下面的例子。

示例-


# Importing Queue Class

from multiprocessing import Queue

fruits = ['Apple', 'Orange', 'Guava', 'Papaya', 'Banana']
count = 1
# creating a queue object
queue = Queue()
print('pushing items to the queue:')
for fr in fruits:
print('item no: ', count, ' ', fr)
queue.put(fr)
count += 1

print('\npopping items from the queue:')
count = 0
while not queue.empty():
print('item no: ', count, ' ', queue.get())
count += 1

输出:

pushing items to the queue:
('item no: ', 1, ' ', 'Apple')
('item no: ', 2, ' ', 'Orange')
('item no: ', 3, ' ', 'Guava')
('item no: ', 4, ' ', 'Papaya')
('item no: ', 5, ' ', 'Banana')

popping items from the queue:
('item no: ', 0, ' ', 'Apple')
('item no: ', 1, ' ', 'Orange')
('item no: ', 2, ' ', 'Guava')
('item no: ', 3, ' ', 'Papaya')
('item no: ', 4, ' ', 'Banana')

解释-

在上面的代码中,我们已经导入了队列类,并初始化了名为水果的列表。接下来,我们将计数指定为 1。count 变量将计算元素的总数。然后,我们通过调用 Queue() 方法来创建队列对象。该对象将用于执行队列中的操作。在 for循环中,我们使用 put() 函数将元素一个接一个地插入到队列中,并随着循环的每次迭代将计数增加 1。

Python 多进程锁类

多进程 Lock 类用于获取进程的锁,这样我们就可以保持另一个进程执行类似的代码,直到锁被释放。锁类主要执行两个任务。第一种是使用 acquire() 功能获取锁,第二种是使用 release() 功能释放锁。

Python 多进程示例

假设我们有多个任务。因此,我们创建了两个队列:第一个队列将维护任务,另一个队列将存储完整的任务日志。下一步是实例化进程来完成任务。如前所述,Queue 类已经同步,所以我们不需要使用 lock 类获取锁。

在下面的例子中,我们将把所有的多进程类合并在一起。让我们看看下面的例子。

示例-


from multiprocessing import Lock, Process, Queue, current_process
import time
import queue

def jobTodo(tasks_to_perform, complete_tasks):
while True:
try:

# The try block to catch task from the queue.
# The get_nowait() function is used to
# raise queue.Empty exception if the queue is empty.

task = tasks_to_perform.get_nowait()

except queue.Empty:

break
else:

# if no exception has been raised, the else block will execute
# add the task completion

print(task)
complete_tasks.put(task + ' is done by ' + current_process().name)
time.sleep(.5)
return True

def main():
total_task = 8
total_number_of_processes = 3
tasks_to_perform = Queue()
complete_tasks = Queue()
number_of_processes = []

for i in range(total_task):
tasks_to_perform.put("Task no " + str(i))

# defining number of processes
for w in range(total_number_of_processes):
p = Process(target=jobTodo, args=(tasks_to_perform, complete_tasks))
number_of_processes.append(p)
p.start()

# completing process
for p in number_of_processes:
p.join()

# print the output
while not complete_tasks.empty():
print(complete_tasks.get())

return True

if __name__ == '__main__':
main()

输出:

Task no 2
Task no 5
Task no 0
Task no 3
Task no 6
Task no 1
Task no 4
Task no 7
Task no 0 is done by Process-1
Task no 1 is done by Process-3
Task no 2 is done by Process-2
Task no 3 is done by Process-1
Task no 4 is done by Process-3
Task no 5 is done by Process-2
Task no 6 is done by Process-1
Task no 7 is done by Process-3

Python 多进程池

Python 多进程池对于跨多个输入值并行执行一个函数至关重要。它还用于将输入数据分布在进程间**(数据并行)**。考虑以下多进程池的示例。

示例-


from multiprocessing import Pool
import time

w = (["V", 5], ["X", 2], ["Y", 1], ["Z", 3])

def work_log(data_for_work):
print(" Process name is %s waiting time is %s seconds" % (data_for_work[0], data_for_work[1]))
time.sleep(int(data_for_work[1]))
print(" Process %s Executed." % data_for_work[0])

def handler():
p = Pool(2)
p.map(work_log, w)

if __name__ == '__main__':
handler()

输出:

Process name is V waiting time is 5 seconds
Process V Executed.
Process name is X waiting time is 2 seconds
Process X Executed.
Process name is Y waiting time is 1 seconds
Process Y Executed.
Process name is Z waiting time is 3 seconds
Process Z Executed.

让我们了解多进程池的另一个例子。

示例- 2


from multiprocessing import Pool
def fun(x):
return x*x

if __name__ == '__main__':
with Pool(5) as p:
print(p.map(fun, [1, 2, 3]))

输出:

[1, 8, 27]

代理对象

代理对象被称为驻留在不同进程中的共享对象。这个对象也被称为代理。多个代理对象可能有相似的引用。代理对象由各种方法组成,这些方法用于调用其引用对象的相应方法。下面是代理对象的例子。

示例-


from multiprocessing import Manager
manager = Manager()
l = manager.list([i*i for i in range(10)])
print(l)
print(repr(l))
print(l[4])
print(l[2:5])

输出:

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<ListProxy object, typeid 'list' at 0x7f063621ea10>
16
[4, 9, 16]

代理对象是可选择的,因此我们可以在进程之间传递它们。这些对象也用于同步的控制级别。

多进程的常用功能

到目前为止,我们已经讨论了使用 Python 进行多进程的基本概念。多进程本身是一个广泛的主题,对于在单个系统中执行各种任务至关重要。我们正在定义一些常用于实现多进程的基本功能。

方法描述
pipe()pipe()函数返回一对连接对象。
pipe()run()方法用于表示流程活动。
start()start()方法用于启动进程。
join([timeout])join()方法用于阻塞进程,直到调用 join()方法的进程终止。超时是可选参数。
is_alive()如果进程是活动的,它将返回。
terminate()顾名思义,它用于终止进程。永远记住 Linux 中使用 terminate() 方法,对于 Windows,我们使用 TerminateProcess() 方法。
kill()这种方法类似于终止(),但使用的是 Unix 上的 SIGKILL 信号。
close()该方法用于关闭进程对象,并释放与之相关的所有资源。
qsize()它返回队列的大致大小。
empty()如果队列为空,则返回
full()如果队列已满,则返回
get_await()这个方法相当于得到(False)
get()此方法用于从队列中获取元素。它从队列中移除并返回一个元素。
put()此方法用于将元素插入队列。
cpu_count()它返回系统中工作的中央处理器的数量。
current_process()它返回对应于当前进程的 Process 对象。
parent_process()它返回对应于当前进程的父进程对象。
task_done()此功能用于指示排队的任务已完成。
join_thread()此方法用于连接后台线程

原文:https://www.javatpoint.com/python-multiprocessing