Python 对于多处理,为什么要按顺序执行
我在网上通过一些例子学习如何并行编程,即如何使用多处理 我在Windows10上运行,带有spyder 3.3.6和python 3.7Python 对于多处理,为什么要按顺序执行,python,python-multiprocessing,Python,Python Multiprocessing,我在网上通过一些例子学习如何并行编程,即如何使用多处理 我在Windows10上运行,带有spyder 3.3.6和python 3.7 import os import time from multiprocessing import Process, Queue def square(numbers, queue): print("started square") for i in numbers: queue.put(i*i) print(
import os
import time
from multiprocessing import Process, Queue
def square(numbers, queue):
print("started square")
for i in numbers:
queue.put(i*i)
print(i*i)
print(f"{os.getpid()}")
def cube(numbers, queue):
print("started cube")
for i in numbers:
queue.put(i*i*i)
print(i*i*i)
print(f"{os.getpid()}")
if __name__ == '__main__':
numbers = range(5)
queue = Queue()
square_process = Process(target=square, args=(numbers,queue))
cube_process = Process(target=cube, args=(numbers,queue))
square_process.start()
cube_process.start()
square_process.join()
cube_process.join()
print("Already joined")
while not queue.empty():
print(queue.get())
我期望队列的输出是混合的或不确定的,因为它取决于进程启动的速度或第一个进程完成所有语句的速度?
理论上,我们可以得到0,1,4,8,9,27,16,64。
但实际输出是按如下顺序进行的0 1. 4. 9 16 0 1. 8. 27
64这里没有什么需要理解的
- 两个进程分别执行square和cube函数。在函数中,它们将维持由for循环控制的顺序
- 在某个时间点上唯一随机的部分是-“哪个进程正在执行并向队列添加什么”。所以它可能是正方形过程在第五次迭代(i=4),而立方体过程在第二次迭代(i=1)李>
- 您正在使用队列的单个实例添加来自两个分别执行square和cube函数的进程的项。队列是先进先出(FIFO),因此当您从队列中获取(在主线程中打印)时,它将保持接收项目的顺序李>
import os
import time
from multiprocessing import Process, Queue
def square(numbers, queue):
print("started square process id is %s"%os.getpid())
for i in numbers:
queue.put("Square of %s is %s "%(i, i*i))
print("square: added %s in queue:"%i)
def cube(numbers, queue):
print("started cube process id is %s"%os.getpid())
for i in numbers:
queue.put("Cube of %s is %s "%(i, i*i*i))
print("cube: added %s in queue:"%i)
if __name__ == '__main__':
numbers = range(15)
queue = Queue()
square_process = Process(target=square, args=(numbers,queue))
cube_process = Process(target=cube, args=(numbers,queue))
square_process.start()
cube_process.start()
square_process.join()
cube_process.join()
print("Already joined")
while not queue.empty():
print(queue.get())
很确定这只是因为旋转一个进程需要一些时间,所以它们倾向于互相追逐 我重写它是为了让作业有更好的并行运行的机会:
from multiprocessing import Process, Queue
from time import time, sleep
def fn(queue, offset, start_time):
sleep(start_time - time())
for i in range(10):
queue.put(offset + i)
if __name__ == '__main__':
queue = Queue()
start_time = time() + 0.1
procs = []
for i in range(2):
args = (queue, i * 10, start_time)
procs.append(Process(target=fn, args=args))
for p in procs: p.start()
for p in procs: p.join()
while not queue.empty():
print(queue.get())
我应该注意到,我得到了输出的不确定性排序,正如您所期望的那样。我在Linux下,所以在Windows下你可能会得到一些不同的东西,但我认为不太可能看起来MisterMiyagi是对的。启动额外的python进程比计算从0到4的平方要昂贵得多:)我已经用lock原语创建了一个版本的代码,现在我们确定进程是同时启动的
import os
from multiprocessing import Process, Queue, Lock
def square(numbers, queue, lock):
print("started square")
# Block here, until lock release
lock.acquire()
for i in numbers:
queue.put(i*i)
print(f"{os.getpid()}")
def cube(numbers, queue, lock):
# Finally release lock
lock.release()
print("started cube")
for i in numbers:
queue.put(i*i*i)
print(f"{os.getpid()}")
if __name__ == '__main__':
numbers = range(5)
queue = Queue()
lock = Lock()
# Activate lock
lock.acquire()
square_process = Process(target=square, args=(numbers,queue,lock))
cube_process = Process(target=cube, args=(numbers,queue,lock))
square_process.start()
cube_process.start()
cube_process.join()
square_process.join()
print("Already joined")
while not queue.empty():
print(queue.get())
我的输出是:
0
0
1
4
1
9
8
16
27
64
这些进程本身并没有做任何CPU繁重或网络受限的事情,所以执行它们所花费的时间可以忽略不计。我的猜测是,当第二个过程开始时,第一个过程已经完成。进程本质上是并行的,但由于您的任务非常琐碎,因此会产生一种错觉,即它们是按顺序运行的。您可以在脚本中引入一些随机性,以查看运行中的并行性
import os
from multiprocessing import Process, Queue
from random import randint
from time import sleep
def square(numbers, queue):
print("started square")
for i in numbers:
if randint(0,1000)%2==0:
sleep(3)
queue.put(i*i)
print(i*i)
print(f"square PID : {os.getpid()}")
def cube(numbers, queue):
print("started cube")
for i in numbers:
if randint(0,1000)%2==0:
sleep(3)
queue.put(i*i*i)
print(i*i*i)
print(f"cube PID : {os.getpid()}")
if __name__ == '__main__':
numbers = range(5)
queue = Queue()
square_process = Process(target=square, args=(numbers,queue))
cube_process = Process(target=cube, args=(numbers,queue))
square_process.start()
cube_process.start()
square_process.join()
cube_process.join()
print("Already joined")
while not queue.empty():
print(queue.get())
在这里,两个进程随机暂停其执行,因此当一个进程暂停时,另一个进程有机会向队列中添加一个数字(multiprocessing.queue是线程和进程安全的)。如果您多次运行此脚本,您将看到队列中项目的顺序并不总是相同的Python有一个GIL,它可以序列化不同线程之间的操作。这些进程运行多长时间?第二个在第一个完成之前就开始了吗?我猜Mistermiagi的解释是正确的。第二个进程在第一个进程完成之前还没有开始,在正方形中放入睡眠(0.005)后,最后一行打印结果0 0 1 8 27 64 1 4 9 16,这确实意味着这两个进程是并行执行的,尽管看起来这两个进程上有某种锁