繁体   English   中英

将未知数量的作业添加到池中,直到作业返回 None

[英]Add unknown number of jobs to pool until a job returns None

假设我们想要发送大量的网络请求,并对我们返回的数据做一些事情。 我们必须对响应进行的数据处理非常繁重,因此我们希望将其并行化:主进程将查询 URL 分配给子进程,然后子进程获取数据并进行一些处理。 够简单! 但我遇到的问题是事先不知道有多少个 URL。 我们知道的唯一方法是当其中一个子进程返回错误时(实际上,当它返回None时)。

我有两种可能的方法,但都有相同的问题:我似乎无法弄清楚如何处理输入列表(要查询的 URL)大小未知(其动态生成)的事实。

尝试#1 :创建一个队列,设置单独的进程来生成 URL(这里它生成索引)并将它们放入队列中。 然后创建侦听此队列并处理链接的子进程(这里就像获取列表的相应项一样简单,但在超出索引时返回 None - 退出场景)。 问题是我不知道如何告诉作者,一旦其中一个进程产生None ,它就应该停止将事物放入队列中。

注意:此脚本将无限运行,因为编写器没有break

from multiprocessing import Pool, Process, Queue

RESPONSES = ["hello", "this", "is", "a", "response", "to", "your", "request"]  # We do not know this length


def send_request(idx):
    try:
        return RESPONSES[idx]
    except IndexError:
        return None


def worker(q):
    while True:
        # Get work from the working queue
        idx = q.get()
        resp = send_request(idx)
        print(resp)


def writer(q):
    idx = 0
    while True:  # How can I stop this when any response is None
        q.put(idx)
        idx += 1


def main():
    work_q = Queue()
    writer_proc = Process(target=writer, args=(work_q,))
    writer_proc.start()

    pool = Pool(3, worker, (work_q,))
    pool.close()
    pool.join()

    writer_proc.join()
    writer_proc.terminate()


if __name__ == '__main__':
    main()

尝试#2:这是一种涉及较少的方法(无队列),它在池上使用apply_async来不断添加可以检查的新 URL。 但是在这里,我不知道一旦其中一名工人发回None ,如何打破那个 while 循环。

from multiprocessing import Pool

RESPONSES = ["hello", "this", "is", "a", "response", "to", "your", "request"]


def send_request(idx):
    try:
        return RESPONSES[idx]
    except IndexError:
        return None


def main():
    with Pool(3) as pool:
        idx = 0
        while True:  # Can't make this loop within fixed range because we do not know how many responses there are
            pool.apply_async(send_request, (idx,))
            idx += 1
            # How do I break out here as soon as a request returns None


if __name__ == '__main__':
    main()

简而言之:如果我事先不知道要完成多少工作,或者更确切地说 - 这取决于工人的反应是否增加更多工作,我如何才能在 Python 中使用一组工人来完成这项工作?

您可以使用multiprocessing.Value

这些创建可以通过子进程访问的共享内存,并反映任何进程对它们所做的任何更改。 因此,像这样创建一个共享标志:

import multiprocessing
from ctypes import c_bool

.
.
.

if __name__ == "__main__":

    # Create flag with inital value True
    flag = multiprocessing.Value(c_bool, "True")

然后将此标志传递给您创建的每个进程。 然后,当您不再想发送请求时,您可以从send_request内部执行以下操作。

flag.value = False

此外,编辑您的writer以检查标志是否在while语句中设置为True (请记住需要使用.value属性访问存储的值!):

while flag.value:

请记住,共享内存不是线程安全的。 虽然这不应该影响您的情况,因为您只是将其用作标志,但您可以在创建标志以在内部使用锁时指定lock=True关键字参数

暂无
暂无

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

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