我写了一个脚本,能够将参数传递给我,我想使用唯一的参数启动多个同时迭代(可能是100多个)。我的计划是编写另一个python脚本,然后启动这些下标/进程,但是要有效,我需要该脚本能够监视下标是否有错误。
是否有任何简单的方法或提供此功能的库?我已经搜寻了一段时间,但没有找到任何好运。创建子进程和多个线程似乎很简单,但是我找不到关于如何与这些线程/子进程进行通信的指南或教程。
答案 0 :(得分:0)
一个更好的方法是利用线程。如果在较大的脚本中创建了要调用的脚本,则可以让主函数根据需要多次调用此脚本,并使线程根据需要报告信息。您可以阅读有关here线程如何工作的一些知识。
答案 1 :(得分:0)
尽管有必要,我还是建议使用threading.Thread或multiprocessing.Process。
在线程/进程之间进行通信的简单方法是使用Queue。多处理模块提供了其他一些在进程之间进行通信的方式(队列,事件,管理器等)
您可以在示例中看到一些基本信息:
import threading
from Queue import Queue
import random
import time
class Worker(threading.Thread):
def __init__(self, name, queue_error):
threading.Thread.__init__(self)
self.name = name
self.queue_error = queue_error
def run(self):
time.sleep(random.randrange(1, 10))
# Do some processing ...
# Report errors
self.queue_error.put((self.name, 'Error state'))
class Launcher(object):
def __init__(self):
self.queue_error = Queue()
def main_loop(self):
# Start threads
for i in range(10):
w = Worker(i, self.queue_error)
w.start()
# Check for errors
while True:
while not self.queue_error.empty():
error_data = self.queue_error.get()
print 'Worker #%s reported error: %s' % (error_data[0], error_data[1])
time.sleep(0.1)
if __name__ == '__main__':
l = Launcher()
l.main_loop()
答案 2 :(得分:0)
就像其他人所说的那样,您必须使用多个进程来实现真正的并行性而不是线程,因为GIL限制会阻止线程并发运行。
如果要使用标准的 multiprocessing 库(基于启动多个进程),建议使用pool of workers。如果我理解正确,则要启动100多个并行实例。在一台主机上启动100多个进程将产生过多的开销。而是创建一个由P个工作程序组成的池,其中P是例如计算机中的核心数,然后将100多个作业提交给该池。这很容易做到,网络上有很多examples。另外,将作业提交到池中时,可以提供回调函数来接收错误。这可能足以满足您的需求(有示例here)。
但是,上一次我在多处理池中无法在多个主机(例如计算机集群)之间分配工作。因此,如果您需要执行此操作,或者需要一个更灵活的通信方案,例如能够在工作人员运行时向控制过程发送更新,那么我的建议是使用charm4py(请注意,一个charm4py开发人员,所以这是我的经验。
使用charm4py,您可以创建N个工作程序,这些工作程序由运行时分布在P个进程之间(跨多个主机工作),并且这些工作程序只需执行远程方法调用即可与控制器进行通信。这是一个小例子:
from charm4py import charm, Chare, Group, Array, ArrayMap, Reducer, threaded
import time
WORKER_ITERATIONS = 100
class Worker(Chare):
def __init__(self, controller):
self.controller = controller
@threaded
def work(self, x, done_future):
result = -1
try:
for i in range(WORKER_ITERATIONS):
if i % 20 == 0:
# send status update to controller
self.controller.progressUpdate(self.thisIndex, i, ret=True).get()
if i == 5 and self.thisIndex[0] % 2 == 0:
# trigger NameError on even-numbered workers
test[3] = 3
time.sleep(0.01)
result = x**2
except Exception as e:
# send error to controller
self.controller.collectError(self.thisIndex, e)
# send result to controller
self.contribute(result, Reducer.gather, done_future)
# This custom map is used to prevent workers from being created on process 0
# (where the controller is). Not strictly needed, but allows more timely
# controller output
class WorkerMap(ArrayMap):
def procNum(self, index):
return (index[0] % (charm.numPes() - 1)) + 1
class Controller(Chare):
def __init__(self, args):
self.startTime = time.time()
done_future = charm.createFuture()
# create 12 workers, which are distributed by charm4py among processes
workers = Array(Worker, 12, args=[self.thisProxy], map=Group(WorkerMap))
# start work
for i in range(12):
workers[i].work(i, done_future)
print('Results are', done_future.get()) # wait for result
exit()
def progressUpdate(self, worker_id, current_step):
print(round(time.time() - self.startTime, 3), ': Worker', worker_id,
'progress', current_step * 100 / WORKER_ITERATIONS, '%')
# the controller can return a value here and the worker would receive it
def collectError(self, worker_id, error):
print(round(time.time() - self.startTime, 3), ': Got error', error,
'from worker', worker_id)
charm.start(Controller)
在此示例中,控制器将在状态更新和错误发生时打印它们。它 完成后将打印所有工作人员的最终结果。工人的成果 失败的将是-1。
启动时给出进程数P。运行时将在可用进程之间分配N个工作程序。在创建工作程序时会发生这种情况,在此特定示例中没有动态负载平衡。
另外,请注意,在charm4py模型中,远程方法调用是异步的,并返回调用者可以阻止的将来,但只有调用线程阻止(而不是整个过程)。
希望这会有所帮助。