Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python多处理:添加到子进程内的队列_Python_Multiprocessing_Python Multiprocessing - Fatal编程技术网

Python多处理:添加到子进程内的队列

Python多处理:添加到子进程内的队列,python,multiprocessing,python-multiprocessing,Python,Multiprocessing,Python Multiprocessing,我想实现一个文件爬虫,将数据存储到Mongo。我想使用多处理作为“移交”阻止任务的一种方式,例如解压缩文件、文件爬网和上传到Mongo。有些任务依赖于其他任务(即,在对文件进行爬网之前需要解压缩文件),因此我希望能够完成必要的任务并将新任务添加到同一任务队列中 以下是我目前拥有的: import multiprocessing class Worker(multiprocessing.Process): def __init__(self, task_queue: multiproc

我想实现一个文件爬虫,将数据存储到Mongo。我想使用
多处理
作为“移交”阻止任务的一种方式,例如解压缩文件、文件爬网和上传到Mongo。有些任务依赖于其他任务(即,在对文件进行爬网之前需要解压缩文件),因此我希望能够完成必要的任务并将新任务添加到同一任务队列中

以下是我目前拥有的:

import multiprocessing


class Worker(multiprocessing.Process):
    def __init__(self, task_queue: multiprocessing.Queue):
        super(Worker, self).__init__()
        self.task_queue = task_queue

    def run(self):
        for (function, *args) in iter(self.task_queue.get, None):
            print(f'Running: {function.__name__}({*args,})')

            # Run the provided function with its parameters in child process
            function(*args)

            self.task_queue.task_done()


def foo(task_queue: multiprocessing.Queue) -> None:
    print('foo')
    # Add new task to queue from this child process
    task_queue.put((bar, 1))


def bar(x: int) -> None:
    print(f'bar: {x}')


def main():
    # Start workers on separate processes
    workers = []
    manager = multiprocessing.Manager()
    task_queue = manager.Queue()
    for i in range(multiprocessing.cpu_count()):
        worker = Worker(task_queue)
        workers.append(worker)
        worker.start()

    # Run foo on child process using the queue as parameter
    task_queue.put((foo, task_queue))

    for _ in workers:
        task_queue.put(None)

    # Block until workers complete and join main process
    for worker in workers:
        worker.join()

    print('Program completed.')


if __name__ == '__main__':
    main()
预期行为:

Running: foo((<AutoProxy[Queue] object, typeid 'Queue' at 0x1b963548908>,))
foo
Running: bar((1,))
bar: 1
Program completed.
Running: foo((<AutoProxy[Queue] object, typeid 'Queue' at 0x1b963548908>,))
foo
Program completed.
Running:foo((,))
福
运行:bar((1,))
酒吧:1
程序完成。
实际行为:

Running: foo((<AutoProxy[Queue] object, typeid 'Queue' at 0x1b963548908>,))
foo
Running: bar((1,))
bar: 1
Program completed.
Running: foo((<AutoProxy[Queue] object, typeid 'Queue' at 0x1b963548908>,))
foo
Program completed.
Running:foo((,))
福
程序完成。

我是多道处理新手,因此非常感谢您的帮助。

正如@FrankYellin所指出的,这是因为
在添加
bar
之前,
任务队列中没有

假设队列不是空的,就是在等待任务完成 在编程期间(在我的例子中是这样),可以使用队列上的
join
方法。根据报告:

阻塞,直到队列中的所有项目都已获取和处理

每当将项目添加到列表中时,未完成任务的计数就会增加 队列每当使用者线程调用时,计数就会下降 task_done(),指示已检索该项及其所有工作 完成了。当未完成任务的计数降至零时,join() 解锁

更新代码如下:

import multiprocessing


class Worker(multiprocessing.Process):
    def __init__(self, task_queue: multiprocessing.Queue):
        super(Worker, self).__init__()
        self.task_queue = task_queue

    def run(self):
        for (function, *args) in iter(self.task_queue.get, None):
            print(f'Running: {function.__name__}({*args,})')

            # Run the provided function with its parameters in child process
            function(*args)

            self.task_queue.task_done() # <-- Notify queue that task is complete


def foo(task_queue: multiprocessing.Queue) -> None:
    print('foo')
    # Add new task to queue from this child process
    task_queue.put((bar, 1))


def bar(x: int) -> None:
    print(f'bar: {x}')


def main():
    # Start workers on separate processes
    workers = []
    manager = multiprocessing.Manager()
    task_queue = manager.Queue()
    for i in range(multiprocessing.cpu_count()):
        worker = Worker(task_queue)
        workers.append(worker)
        worker.start()

    # Run foo on child process using the queue as parameter
    task_queue.put((foo, task_queue))

    # Block until all items in queue are popped and completed
    task_queue.join() # <---

    for _ in workers:
        task_queue.put(None)

    # Block until workers complete and join main process
    for worker in workers:
        worker.join()

    print('Program completed.')


if __name__ == '__main__':
    main()
导入多处理
类工作者(多处理.Process):
def_uuuinit_uuu(self,task_队列:multiprocessing.queue):
超级(工作者,自我)。\uuuu初始化
self.task\u queue=任务队列
def运行(自):
对于iter(self.task_queue.get,无)中的(函数,*args):
打印(f'Running:{function.{name}({*args,}))
#在子进程中运行提供的函数及其参数
函数(*args)
self.task_queue.task_done()#无:
打印('foo')
#从此子进程向队列添加新任务
任务队列放置((条,1))
定义栏(x:int)->无:
打印(f'bar:{x}')
def main():
#在不同的流程上启动工人
工人=[]
manager=multiprocessing.manager()
task_queue=manager.queue()
对于范围内的i(multiprocessing.cpu\u count()):
工人=工人(任务队列)
workers.append(worker)
worker.start()
#使用队列作为参数在子进程上运行foo
task_queue.put((foo,task_queue))
#阻塞,直到队列中的所有项目都弹出并完成

task_queue.join()#正如@FrankYellin所指出的,这是因为在可以添加
bar
之前,
None
被放入
task_queue

假设队列不是空的,就是在等待任务完成 在编程期间(在我的例子中是这样),可以使用队列上的
join
方法。根据报告:

阻塞,直到队列中的所有项目都已获取和处理

每当将项目添加到列表中时,未完成任务的计数就会增加 队列每当使用者线程调用时,计数就会下降 task_done(),指示已检索该项及其所有工作 完成了。当未完成任务的计数降至零时,join() 解锁

更新代码如下:

import multiprocessing


class Worker(multiprocessing.Process):
    def __init__(self, task_queue: multiprocessing.Queue):
        super(Worker, self).__init__()
        self.task_queue = task_queue

    def run(self):
        for (function, *args) in iter(self.task_queue.get, None):
            print(f'Running: {function.__name__}({*args,})')

            # Run the provided function with its parameters in child process
            function(*args)

            self.task_queue.task_done() # <-- Notify queue that task is complete


def foo(task_queue: multiprocessing.Queue) -> None:
    print('foo')
    # Add new task to queue from this child process
    task_queue.put((bar, 1))


def bar(x: int) -> None:
    print(f'bar: {x}')


def main():
    # Start workers on separate processes
    workers = []
    manager = multiprocessing.Manager()
    task_queue = manager.Queue()
    for i in range(multiprocessing.cpu_count()):
        worker = Worker(task_queue)
        workers.append(worker)
        worker.start()

    # Run foo on child process using the queue as parameter
    task_queue.put((foo, task_queue))

    # Block until all items in queue are popped and completed
    task_queue.join() # <---

    for _ in workers:
        task_queue.put(None)

    # Block until workers complete and join main process
    for worker in workers:
        worker.join()

    print('Program completed.')


if __name__ == '__main__':
    main()
导入多处理
类工作者(多处理.Process):
def_uuuinit_uuu(self,task_队列:multiprocessing.queue):
超级(工作者,自我)。\uuuu初始化
self.task\u queue=任务队列
def运行(自):
对于iter(self.task_queue.get,无)中的(函数,*args):
打印(f'Running:{function.{name}({*args,}))
#在子进程中运行提供的函数及其参数
函数(*args)
self.task_queue.task_done()#无:
打印('foo')
#从此子进程向队列添加新任务
任务队列放置((条,1))
定义栏(x:int)->无:
打印(f'bar:{x}')
def main():
#在不同的流程上启动工人
工人=[]
manager=multiprocessing.manager()
task_queue=manager.queue()
对于范围内的i(multiprocessing.cpu\u count()):
工人=工人(任务队列)
workers.append(worker)
worker.start()
#使用队列作为参数在子进程上运行foo
task_queue.put((foo,task_queue))
#阻塞,直到队列中的所有项目都弹出并完成

task_queue.join()#在任何工作人员有机会将自己的元素添加到队列之前,您正在为每个工作人员将
None
放入队列(导致他们结束)。事实上,你有一个有趣的问题。在每个工作进程都处于等待状态之前,无法停止任何工作进程。只要有一个工人还在工作,就有可能给队列增加更多的工作。我不确定解决方案。这并不重要,但代码会显示
print('Program completed')
,而您的输出是
程序结束。
@lenin Whoops,想引入更好的日志记录。修正了。@FrankYellin,啊,是的,完全有道理。我进一步研究了等待,直到队列清空,并相信我已经找到了解决方案。谢谢。在每个工作人员有机会将自己的元素添加到队列之前,您正在为每个工作人员将一个
None
放入队列(导致他们结束)。事实上,你有一个有趣的问题。在每个工作进程都处于等待状态之前,无法停止任何工作进程。只要有一个工人还在工作,就有可能给队列增加更多的工作。我不确定解决方案。这并不重要,但代码会显示
print('Program completed')
,而您的输出是
程序结束。
@lenin Whoops,想引入更好的日志记录。修正了。@FrankYellin,啊,是的,完全有道理。我已经深入研究了等待时间