2017-10-15 101 views
0

早些时候,我尝试在python中使用线程模块来创建多个线程。然后我了解了GIL以及它如何不允许在一台机器上利用多个CPU内核。所以现在我试图做多处理(我不严格需要单独的线程)。使用Python产生多个进程

这是我写的示例代码,以查看是否正在创建不同的进程。但是从下面的输出中可以看出,我每次都得到相同的进程ID。所以多个进程没有被创建。我错过了什么?

import multiprocessing as mp 
import os 

def pri(): 
    print(os.getpid()) 

if __name__=='__main__': 

    # Checking number of CPU cores 
    print(mp.cpu_count()) 

    processes=[mp.Process(target=pri()) for x in range(1,4)] 

    for p in processes: 
     p.start() 

    for p in processes: 
     p.join() 

输出:

4 
12554 
12554 
12554 
+2

删除第在'target = pri()'上输入e'()' –

回答

2

Process类需要一个可调用作为其目标。

而不是在单独的进程中运行该函数,而是调用它并将结果(本例中为None)传递到Process类。

只需更改如下:

mp.Process(target=pri()) 

有:

mp.Process(target=pri) 
+0

这仍然返回相同的PID。它甚至不会将它打印到屏幕上,因为它在子进程中运行。 – Vinny

+0

我刚刚尝试了代码,我得到3个不同的PID。取决于操作系统,它可能会重新使用PID,在这种情况下,它与OP无关,因为范围是测试'multiprocessing'库。 – noxdafox

0

由于子进程运行在不同的过程中,你不会看到他们的打印报表。他们也不共享相同的内存空间。你传递pri()到目标,它需要pri。您需要通过一个可调用对象,而不是执行它。

您看到的打印件是主线程执行的一部分。因为您通过pri(),代码实际上执行。您需要更改代码,以便pri函数返回值,而不是打印它。

然后,你需要实现一个queue,其中所有的线程它和他们做的时候,你的主线程读取队列。

multiprocessing模块的一个很好的功能是Pool对象。它允许你创建一个线程池,然后使用它。这更方便。

我试过了你的代码,事情是该命令执行得太快,所以操作系统重用了PID。如果您在pri函数中添加time.sleep(1),它将按您的预期工作。

这仅适用于Windows。下面的例子是在Windows平台上进行的。在Unix上像机器一样,你不需要睡眠。

更方便的解决方案是这样的:

from multiprocessing import Pool 
from time import sleep 
import os 

def pri(x): 
    sleep(1) 
    return os.getpid() 

def use_procs(): 
    p_pool = Pool(4) 
    p_results = p_pool.map(pri, [_ for _ in range(1,4)]) 
    p_pool.close() 
    p_pool.join() 
    return p_results 

if __name__ == '__main__': 
    res = use_procs() 
    for r in res: 
     print r 

如果没有睡眠:

==================== RESTART: C:/Python27/tests/test2.py ==================== 
6576 
6576 
6576 
>>> 

与睡眠:

==================== RESTART: C:/Python27/tests/test2.py ==================== 
10396 
10944 
9000 
+0

如果您使用“Pool”,任务将由第一个可用工作人员处理。由于Windows使用'spawn'启动方法,进程的启动速度比Unix(默认情况下使用'fork')慢。因此,第一个员工流程在其他员工准备好之前“抢走”了所有任务。这就是为什么你看到只有第一个PID被打印在你的逻辑中。 – noxdafox

+0

你说得对。我只是在Linux机器上尝试过它,它确实打印了唯一的PID。但是,除了打印之外,为了使进程与主线程通信,它必须使用通信接口(队列,套接字等)。使用'Pool'可以简化多处理过程。 – Vinny

+0

这取决于用例,有时你只需要旋转诸如HTTP服务器之类的东西。在这些情况下,你并不关心函数返回的内容。对于许多用例来说,进程都是很好的,我个人最喜欢的是他们提供给应用程序的隔离。如果另一个进程中的逻辑崩溃,您的应用程序将不受影响。使用线程或协程无法轻松实现这一点。 – noxdafox

相关问题