我的目标是并行计算多个数据点,并将它们异步写入IO设备。数据点不能只由它们自己编写,而是需要包装;更确切地说,我正在编写一个JSON数组,并且需要在结构周围添加[]
符号。
我目前的方法是使用multiprocessing.Pool
和apply_async来计算数据点。使用回调函数,然后将数据点发送到multiprocessing.Queue
,同时单独的线程同步从队列中提取元素并将它们写入IO设备。
我可能需要使用SIGINT取消进程。在这种情况下,我希望计算安全地完成,即停止计算所有Pool
进程,但完成编写队列中的所有剩余元素和]
符号。
到目前为止,我没有找到解决问题的有效方法。在目前的状态,我的两个问题是:
SIGINT_handler
但该进程不会终止。我无法验证它的来源,但我认为它可能是队列中的死锁?我不知道如何防止这种情况。pool.terminate()
向其所有子进程发送SIGTERM。这显然会在每一个中引起KeyboardInterrupt异常,使十二个堆栈跟踪混乱终端。我的代码可以在下面找到。
# Initialize the worker pool and necessary variables.
pool = multiprocessing.Pool(os.cpu_count() - 1)
data_queue = multiprocessing.Queue()
counter_lock = threading.Lock()
threads_todo = args.autnum
# This function is executed after each successful experiment.
def apply_finished(data):
data_queue.put(data)
with counter_lock:
nonlocal threads_todo
threads_todo -= 1
# Start the pool.
for i in range(args.autnum):
pool.apply_async(collect_data, (args,), callback=apply_finished)
pool.close()
# This function is called if SIGINT is send to this process.
def SIGINT_handler(sig, frame):
sys.stderr.write("SIGINT received. Cancelling...")
sys.stderr.flush()
pool.terminate()
with counter_lock:
nonlocal threads_todo
threads_todo = 0
signal.signal(signal.SIGINT, SIGINT_handler)
# Write the data to stdout until all workers terminate or a SIGINT is received.
sys.stdout.write("[\n")
while threads_todo > 0 or not data_queue.empty():
try:
data = data_queue.get(True, 1)
s = data.decode('utf-8')
sys.stdout.write(s)
sys.stdout.flush()
except queue.Empty:
data = None
sys.stdout.write("]")