繁体   English   中英

无法从多处理中的 prom 父进程获取另一个子进程中的数据 python

[英]Failed to get data in another child from prom parent process in multiprocessing python

如果我声明一个 Queue object 全局级别并且我没有将它传递给多处理中的目标 function 并将一些数据放入 Queue object 并且无法进入主线程。 当我的进程在队列 object 中调用 get 方法时,它处于连续循环中,因为它正在等待队列 object 中的一些数据。

    from multiprocessing import Process, Queue
    
    def getretsults(*kwargs):
        print("Executing Get Results..........")
        res = []
        for i in kwargs[0]:
            res.append(i**i)
        if len(kwargs) >= 1:
            q = kwargs[1]
        print(f"{id(q) = }")
        q.put(res)
    
    
    q = Queue()
    
    
    def main_process():
        a =256
        b = 900
        print("Executing Main Process.........")
        args = [
            range(1,6),
            range(6,11),
            range(11,16)
        ]
    
        print(f"{id(args) = }")
    
        process_ = []
        if __name__ == '__main__':
            q = Queue()
            for x in args:
                p = Process(target=getretsults, args=(x,))
                process_.append(p)
                p.start()
    
            for x_ in process_:
                x_.join()
    
    
            print(q.get())
    
    main_process()

我问过你在什么操作系统下运行,但没有收到回复。 我一开始会假设它是一个使用fork方法创建子进程的平台(比如Linux)。 我将展示第二个版本,它可以在 Linux 或 Windows 下运行。

您的代码有几个问题,有些是次要的,有些是主要的。

  1. getresults的参数名称是kwargs并且表示传递的所有位置参数的可迭代(元组)。 这是一个小问题(不是导致错误的任何原因),但约定是将此参数命名为args并使用名称kwargs来接收关键字参数。
  2. 如果您在使用fork创建新进程的操作系统下运行,那么您可以将q声明为全局的,子进程将继承对此队列实例的引用。 相反,您也可以创建一个非全局队列并将其作为参数传递。 但是在main_process中你有q = Queue()而你没有声明q全局。 这导致创建一个新的局部变量q并且没有将这个新队列实例分配给全局q变量。 因此,放置结果的q与主进程从中获取的q不同。 这是一个主要错误。
  3. 在使用get检索所有元素之前,您绝不能join将元素放入多处理队列的子进程。 否则,您可能会挂起,因为在检索到这些元素之前,子进程通常无法终止。
  4. 我不确定你想用print(f"{id(args) = }")完成什么。 如果您正在尝试打印 ID,则可能是print(f"id(args} = {id(args)}")
  5. getresults你的测试if len(kwargs) >= 1:应该是if len(kwargs) > 1:
  6. getresults ,取决于队列实例是否已作为第二个参数传递,应该确定您是将结果放入传递的队列参数还是已声明的全局队列。
  7. 如果你运行在Windows或任何使用spawn方法创建子进程的平台下,你必须将队列实例作为参数传递。 这是因为每个子进程都将重新执行全局级别的q = Queue() ,因此每个子进程肯定会彼此放入不同的队列,并且主进程正在执行的队列与之相反。

通过这些更正,我们最终得到:

仅限 Linux 版本

from multiprocessing import Process, Queue

q = Queue()

def getretsults(*args):
    print("Executing Get Results..........")
    res = []
    for i in args[0]:
        res.append(i**i)
    if len(args) > 1: # Must be >, not >=
        result_q = args[1]
    else:
        result_q = q # global q
    print(f'id(result_q) = {id(result_q)}')
    result_q.put(res)


def main_process():
    global q

    a =256
    b = 900
    print("Executing Main Process.........")
    args = [
        range(1,6),
        range(6,11),
        range(11,16)
    ]

    print(f"id(args) = {id(args)}")

    process_ = []
    q = Queue()
    for x in args:
        p = Process(target=getretsults, args=(x,))
        process_.append(p)
        p.start()

    for _ in range(len(args)):
        print(q.get())

    for x_ in process_:
        x_.join()

main_process()

印刷:

Executing Main Process.........
id(args) = 140481897185024
Executing Get Results..........
id(result_q) = 140481897250768
Executing Get Results..........
id(result_q) = 140481897250768
Executing Get Results..........
id(result_q) = 140481897250768
[1, 4, 27, 256, 3125]
[285311670611, 8916100448256, 302875106592253, 11112006825558016, 437893890380859375]
[46656, 823543, 16777216, 387420489, 10000000000]

独立于操作系统的版本

from multiprocessing import Process, Queue


def getretsults(x, q):
    print("Executing Get Results..........")
    res = []
    for i in x:
        res.append(i**i)
    print(f'id(q) = {id(q)}')
    q.put(res)


def main_process():
    a =256
    b = 900
    print("Executing Main Process.........")
    args = [
        range(1,6),
        range(6,11),
        range(11,16)
    ]

    print(f"id(args) = {id(args)}")

    process_ = []
    q = Queue()
    for x in args:
        p = Process(target=getretsults, args=(x, q))
        process_.append(p)
        p.start()

    for _ in range(len(args)):
        print(q.get())

    for x_ in process_:
        x_.join()

if __name__ == '__main__':
    main_process()

印刷:

Executing Main Process.........
id(args) = 1775036479808
Executing Get Results..........
id(q) = 2365890922528
Executing Get Results..........
id(q) = 2128150562848
Executing Get Results..........
id(q) = 2368897255456
[46656, 823543, 16777216, 387420489, 10000000000]
[285311670611, 8916100448256, 302875106592253, 11112006825558016, 437893890380859375]
[1, 4, 27, 256, 3125]

请注意,队列的 id 对于每个子进程都是不同的,并且子进程将结果放入队列的顺序是不同的,并且不能依赖于使用显式Process实例放入队列。

使用多处理池的版本

这里我们可以保证返回结果的顺序(注意我包括了一些代码改进):

from multiprocessing import Pool

# Renamed worker function:
def getresults(x):
    print("Executing Get Results..........", flush=True)
    return [i ** i for i in x] # More efficiently expressed!


def main_process():
    print("Executing Main Process.........", flush=True)
    args = [
        range(1,6),
        range(6,11),
        range(11,16)
    ]

    with Pool(3) as pool:
        results = pool.map(getresults, args)
    for result in results:
        print(result)

if __name__ == '__main__':
    main_process()

印刷:

Executing Main Process.........
Executing Get Results..........
Executing Get Results..........
Executing Get Results..........
[1, 4, 27, 256, 3125]
[46656, 823543, 16777216, 387420489, 10000000000]
[285311670611, 8916100448256, 302875106592253, 11112006825558016, 437893890380859375]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM