【问题标题】:multiprocessing process gets started directly at creation多处理过程在创建时直接启动
【发布时间】:2019-05-22 11:32:29
【问题描述】:

您好,我在 python 3.7 中遇到了多处理问题 我做了一个监听器,它应该等待服务器的响应而不阻塞程序的其余部分(异步通信):

self = cl.appendSend('bar', base_list)
print("client erstellt neuen nebenläufigen listener, für die Antwort des Servers")
multiprocessing.set_start_method("spawn")
queue = multiprocessing.Queue()
process = multiprocessing.Process(target = cl.appendResponse(), args=(self))
process.start()
print("listener aktiv")

thread = threading.Thread(target= waitingPrinter(), args=(process, queue))
print(thread)

是一切开始的地方 但是process = multiprocessing.Process(target = cl.appendResponse(), args=(self)) 行启动一次,运行一次,然后在完成后再次运行。调试器永远不会离开这一行。

进程中运行的方法是:

 def appendResponse(self):
        print("nebenläufiger listener aktiv")
        msgrcv = self.chan.receive_from(self.server)
        print("nebenläufiger listener hat Antwort erhalten")
        return msgrcv  # pass it to caller

遗憾的是,由于版权问题,我无法真正发布更多内容,但该方法第一次运行良好,第二次失败并显示以下消息: Traceback(最近一次调用最后一次):

> File "D:/Verteile Systeme 2/neues Lab/git/vs2lab/lab2/rpc/runcl.py",
> line 27, in <module>
>     process = multiprocessing.Process(target = cl.appendResponse(), args=(self))   File "C:\Program Files
> (x86)\Python37-32\lib\multiprocessing\process.py", line 82, in
> __init__
>     self._args = tuple(args) TypeError: 'Client' object is not iterable

所以我想知道,为什么cl.appendResponse() 的进程甚至在绑定到进程时就开始了并且不等待process.start(),如果还没有回答,为什么它会直接运行一秒钟时间。当然,我该如何解决这个问题。

还有没有办法用线程替换处理并仍然获得返回值? 我在处理和返回值方面遇到了很多麻烦。

【问题讨论】:

    标签: python multithreading python-multiprocessing


    【解决方案1】:

    target = cl.appendResponse() 将运行该函数并将结果返回给目标。 正确的语法是target=cl.appendResponse,它将告诉 Process 在 start() 上运行 cl.appendResponse。

    【讨论】:

      【解决方案2】:

      philipp 在他们的answer 中正确说明了该过程明显立即执行的原因。
      Processtarget 参数采用可调用对象,该对象将由 run() 方法调用。您的代码通过 self.chan.receive_from(self.server) 返回的任何内容。
      process = multiprocessing.Process(target = cl.appendResponse(), args=(self)) 行中或从行中没有运行子进程。您的方法在主进程中运行并阻止它。
      附带说明:您的thread 会遇到完全相同的问题,原因相同:thread = threading.Thread(target= waitingPrinter(), args=(process, queue))

      在您的方法在主进程中完成执行后,您的进程对象的初始化会引发TypeError inside the __init__ method of the BaseProcess class
      您将参数self 传递给您的流程,但您做错了。 args 参数需要一个参数元组。如果只指定了一个值,则通过文字创建元组需要一个尾随逗号:args=(self,)。您的代码有效地传递了self,即直接传递Client 对象,这是不可迭代的,因此会导致错误。
      在您的情况下,appendResponse 似乎是Client 对象的绑定方法。它将通过 Python 类系统的内部工作原理接收 self 参数。通过该过程显式传递它会引发另一个TypeError,用于将两个位置参数传递给一个只需要一个的方法。除非appendSend 返回的不是Client 实例cl,否则您调用它时,请在流程实例化中删除args 参数。

      另一方面:启动方法spawn 是Windows 上唯一可用的方法,因此是默认方法。除非您的代码需要使用该启动方法在 Unix 下运行,否则此行是多余的:multiprocessing.set_start_method("spawn")

      【讨论】:

      • 谢谢,很高兴知道出了什么问题,而且我确实以错误的方式发送了参数。我更改了它,明天我可以再次与服务器联系时尝试它。由于您似乎比我更了解 python 的工作原理,我想知道您如何看待我的构造,线程正在获取进程的响应,然后将其打印出来。我的假设是线程将被启动并且什么都不做,因为程序的其余部分继续运行并且仅在进程返回响应时启动。我的假设是否正确?
      • @Etaila 这有点难说,因为我不知道waitingPrinter 会发生什么,但根据我从您的描述中了解到的情况,您的假设似乎是正确的。但是,由于您的进程似乎只是在等待来自服务器的一些数据,为什么不完全放弃它并在线程中执行所有操作呢?进程的任务似乎是 I/O 绑定的,所以 Python 的全局解释器锁在这里应该不是问题。当您将Client 对象直接传递给waitingPrinter 时,您可以调用其中的方法并在收到结果后直接处理结果。
      • @shmee waitingPrinter 只是使用 process.join 和 'print()' 在控制台中写入响应而已。而我将这两者分开的原因是,进程来自另一个类,它只处理与服务器的通信、结果的打印,或者在实际任务中,对响应的进一步处理是另一个类,其中 waitingPrinter被定义在。而且我感觉不舒服,基本上是在任务的上下文中完成客户端的报废。如果它是一个私人项目,我可能会在这个过程中完成所有工作。
      • @Etaila 哦,现在,我看得更近了,您不必将该参数传递给您的流程实例化。事实上,当调用process.start() 时,它会引发另一个TypeErrorappendResponse 似乎是您的 Client 对象的绑定方法,因此它将按原样传递。它将在内部接收self 中引用的实例。再次传递self 将让您最终使用两个位置参数调用该方法,而它只接受一个。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-13
      • 2012-12-30
      • 1970-01-01
      • 1970-01-01
      • 2017-05-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多