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