[英]Python - multiprocessing threads don't close when using Queue
这适用于Python 3.x.
我正在以300块的形式从CSV文件加载记录,然后生成工作线程以将它们提交到REST API。 我将HTTP响应保存在队列中,这样我就可以在处理完整个CSV文件后获得跳过记录数的计数。 但是,在我向我的工作人员添加了一个队列后,线程似乎不再关闭了。 我想监视线程的数量有两个原因:(1)一旦完成,我可以计算并显示跳过计数和(2)我想增强我的脚本产生不超过20个左右的线程,所以我不要耗尽内存。
我有两个问题:
q.put()
时保持活动状态? 这是我的代码(有些简化,因为我无法分享我正在调用的API的确切细节):
import requests, json, csv, time, datetime, multiprocessing
TEST_FILE = 'file.csv'
def read_test_data(path, chunksize=300):
leads = []
with open(path, 'rU') as data:
reader = csv.DictReader(data)
for index, row in enumerate(reader):
if (index % chunksize == 0 and index > 0):
yield leads
del leads[:]
leads.append(row)
yield leads
def worker(leads, q):
payload = {"action":"createOrUpdate","input":leads}
r = requests.post(url, params=params, data=json.dumps(payload), headers=headers)
q.put(r.text) # this puts the response in a queue for later analysis
return
if __name__ == "__main__":
q = multiprocessing.Queue() # this is a queue to put all HTTP responses in, so we count the skips
jobs = []
for leads in read_test_data(TEST_FILE): # This function reads a CSV file and provides 300 records at a time
p = multiprocessing.Process(target=worker, args=(leads,q,))
jobs.append(p)
p.start()
time.sleep(20) # checking if processes are closing automatically (they don't)
print(len(multiprocessing.active_children())) ## always returns the number of threads. If I remove 'q.put' from worker, it returns 0
# The intent is to wait until all workers are done, but it results in an infinite loop
# when I remove 'q.put' in the worker it works fine
#while len(multiprocessing.active_children()) > 0: #
# time.sleep(1)
skipped_count = 0
while not q.empty(): # calculate number of skipped records based on the HTTP responses in the queue
http_response = json.loads(q.get())
for i in http_response['result']:
if (i['status'] == "skipped" and i['reasons'][0]['code'] == "1004"):
skipped_count += 1
print("Number of records skipped: " + str(skipped_count))
这很可能是因为这个记录的multiprocessing.Queue
怪癖.Queue:
请记住,将项目放入队列的进程将在终止之前等待,直到所有缓冲的项目由“feeder”线程提供给底层管道。 (子进程可以调用队列的
cancel_join_thread()
方法以避免此行为。)这意味着无论何时使用队列,您都需要确保在加入进程之前最终删除已放入队列的所有项目。 否则,您无法确定已将项目放入队列的进程将终止。 还要记住,非守护进程会自动加入。
基本上,你需要确保你get()
所有从项目Queue
,以保证所有的流程put
东西放到该Queue
就可以退出。
我认为在这种情况下,您最好使用multiprocessing.Pool
,并将所有作业提交到multiprocessing.Pool.map
。 这大大简化了事情,并使您可以完全控制运行的进程数:
def worker(leads):
payload = {"action":"createOrUpdate","input":leads}
r = requests.post(url, params=params, data=json.dumps(payload), headers=headers)
return r.text
if __name__ == "__main__":
pool = multiprocessing.Pool(multiprocessing.cpu_count() * 2) # cpu_count() * 2 processes running in the pool
responses = pool.map(worker, read_test_data(TEST_FILE))
skipped_count = 0
for raw_response in responses:
http_response = json.loads(raw_response)
for i in http_response['result']:
if (i['status'] == "skipped" and i['reasons'][0]['code'] == "1004"):
skipped_count += 1
print("Number of records skipped: " + str(skipped_count))
如果您担心将read_test_data(TEST_FILE)
转换为列表(使用Pool.map
所需read_test_data(TEST_FILE)
的内存成本,则可以使用Pool.imap
。
编辑:
正如我在上面的评论中提到的,这个用例看起来像是I / O绑定的,这意味着你可以通过使用multiprocessing.dummy.Pool
(它使用线程池而不是进程池)来看到更好的性能。 试一试,看看哪个更快。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.