【发布时间】:2015-01-21 14:38:58
【问题描述】:
TL;DR:使用线程和多处理以及单线程运行代码后得到不同的结果。需要有关故障排除的指导。
您好,如果这可能有点过于笼统,我提前道歉,但我需要一些帮助来解决问题,我不确定如何最好地继续。
故事是这样的;我有一堆数据被索引到 Solr 集合(约 2.5 亿个项目)中,该集合中的所有项目都有一个 sessionid。某些项目可以共享相同的会话 ID。我正在梳理集合以提取具有相同会话的所有项目,稍微处理数据并吐出另一个 JSON 文件以供稍后索引。
代码有两个主要功能: proc_day - 接受一天并处理当天的所有会话 和 proc_session - 完成单个会话需要发生的所有事情。
多处理是在proc_day上实现的,所以每一天都会被一个单独的进程处理,proc_session函数可以用线程来运行。下面是我在下面用于线程/多处理的代码。它接受一个函数、一个参数列表和线程/多进程的数量。然后它将根据输入参数创建一个队列,然后创建进程/线程并让它们通过它。我没有发布实际代码,因为它通常运行良好的单线程没有任何问题,但如果需要可以发布它。
autoprocs.py
import sys
import logging
from multiprocessing import Process, Queue,JoinableQueue
import time
import multiprocessing
import os
def proc_proc(func,data,threads,delay=10):
if threads < 0:
return
q = JoinableQueue()
procs = []
for i in range(threads):
thread = Process(target=proc_exec,args=(func,q))
thread.daemon = True;
thread.start()
procs.append(thread)
for item in data:
q.put(item)
logging.debug(str(os.getpid()) + ' *** Processes started and data loaded into queue waiting')
s = q.qsize()
while s > 0:
logging.info(str(os.getpid()) + " - Proc Queue Size is:" + str(s))
s = q.qsize()
time.sleep(delay)
for p in procs:
logging.debug(str(os.getpid()) + " - Joining Process {}".format(p))
p.join(1)
logging.debug(str(os.getpid()) + ' - *** Main Proc waiting')
q.join()
logging.debug(str(os.getpid()) + ' - *** Done')
def proc_exec(func,q):
p = multiprocessing.current_process()
logging.debug(str(os.getpid()) + ' - Starting:{},{}'.format(p.name, p.pid))
while True:
d = q.get()
try:
logging.debug(str(os.getpid()) + " - Starting to Process {}".format(d))
func(d)
sys.stdout.flush()
logging.debug(str(os.getpid()) + " - Marking Task as Done")
q.task_done()
except:
logging.error(str(os.getpid()) + " - Exception in subprocess execution")
logging.error(sys.exc_info()[0])
logging.debug(str(os.getpid()) + 'Ending:{},{}'.format(p.name, p.pid))
autothreads.py:
import threading
import logging
import time
from queue import Queue
def thread_proc(func,data,threads):
if threads < 0:
return "Thead Count not specified"
q = Queue()
for i in range(threads):
thread = threading.Thread(target=thread_exec,args=(func,q))
thread.daemon = True
thread.start()
for item in data:
q.put(item)
logging.debug('*** Main thread waiting')
s = q.qsize()
while s > 0:
logging.debug("Queue Size is:" + str(s))
s = q.qsize()
time.sleep(1)
logging.debug('*** Main thread waiting')
q.join()
logging.debug('*** Done')
def thread_exec(func,q):
while True:
d = q.get()
#logging.debug("Working...")
try:
func(d)
except:
pass
q.task_done()
在 python 在不同的多处理/线程配置下运行后,我遇到了验证数据的问题。有很多数据,所以我真的需要让多处理工作。这是我昨天的测试结果。
Only with multiprocessing - 10 procs:
Days Processed 30
Sessions Found 3,507,475
Sessions Processed 3,514,496
Files 162,140
Data Output: 1.9G
multiprocessing and multithreading - 10 procs 10 threads
Days Processed 30
Sessions Found 3,356,362
Sessions Processed 3,272,402
Files 424,005
Data Output: 2.2GB
just threading - 10 threads
Days Processed 31
Sessions Found 3,595,263
Sessions Processed 3,595,263
Files 733,664
Data Output: 3.3GB
Single process/ no threading
Days Processed 31
Sessions Found 3,595,263
Sessions Processed 3,595,263
Files 162,190
Data Output: 1.9GB
这些计数是通过日志文件中的 grepping 和 counties 条目收集的(每个主进程 1 个)。跳出来的第一件事是处理的天数不匹配。但是,我手动检查了日志文件,似乎缺少一个日志条目,日志条目后面有表明这一天已实际处理。我不知道为什么它被省略了。
我真的不想写更多的代码来验证这个代码,这似乎是一种可怕的浪费时间,有没有其他选择?
【问题讨论】:
-
我认为人们会提供帮助,但只是关于以下内容的评论:“我真的不想编写更多代码来验证此代码,这似乎是在浪费时间” i>:如果数据分析很重要,那么您最好 100% 确保您的处理管道按照预期的方式工作。相应的测试代码可能很容易比您正在测试的代码更复杂。
-
"Sessions Found 3,595,263 , Sessions Processed 3,595,263 " -- 这是预期的输出吗?意思是,“单进程/无线程”和“仅线程 - 10 个线程”是否按预期工作?什么是“文件 162,140,数据输出:1.9G”?这些数字是描述输入还是输出?这对我们很重要吗?
-
只是一个警告:
if threads < 0: return "Thead Count not specified"本身并不能真正让人想要调试你的代码。负数表示“未指定”?在 Python 世界中,这就是语义 B$。默认情况下,不提供参数会给你一个很好的例外。并将错误消息作为字符串返回?那么,您将这个函数的返回值指定为None还是错误消息?在尝试实现复杂的并发构造之前,您确实应该深入研究 Python 异常。
标签: python multithreading solr multiprocessing python-multiprocessing