首页 > 解决方案 > 当被要求运行时,Python 块中的多处理

问题描述

我正在开发一个执行轮询的程序,出于性能原因,我需要在单独的进程中完成轮询。该程序很长,但我设法将其减少到最低限度,以便更容易理解。它是一个两种状态机,一个是空闲的,另一个打印单独的进程已放入队列的值。

所以问题是,当命令多处理进程开始时,一切都冻结了。只有进程疯狂运行,程序没有反应。

self.queue = Queue() #initialize a Queue
self.slave_process = Process(
    target=self.write,
    args =(self.queue,)) #Define our queue filler process
# Here is when it freezes
self.slave_process.start() #Ask the process to start

请查看代码注释以获得进一步的解释。

你能帮我解决这个问题吗?

import time
import threading
import tkinter as tk
from datetime import datetime
from multiprocess import Process
from multiprocessing import Queue

class Main(object):

    # This is a very normal object initializer
    # I will use a tkinter GUI to use a button
    def __init__(self):
        self.root = tk.Tk() #The root of tkinter
        self.button1 = tk.Button(self.root, 
            text="Connect", command=self.btConnect,
            padx=5, pady=5) #My button that executes btConnect()
        self.button1.pack() #We pack the button
        self.state = "idle" #Indicator of the initial state of the FSM
        self.root.mainloop() #Instruction to make tkinter GUI run

    # This state does pretty much nothing except print its name
    # It should terminate when the self.state name changes
    def stIdle(self):
        while self.state == "idle":
            print("stIdle")

    # This state prints its name and, 
    # if there is a value in the queue it pops it and prints it
    def stConnect(self):
        while state == "connected":
            print("stConnect")
            if not self.queue.empty():
                print(self.queue.get())

    # This is the code the button executes
    def btConnect(self):
        print("acConnect") #First print something so we know it happened
        if self.state == "idle": #if the state was idle
            self.queue = Queue() #initialize a Queue
            self.slave_process = Process(
                target=self.write,
                args =(self.queue,)) #Define our queue filler process
            # Here is when it freezes
            self.slave_process.start() #Ask the process to start
            time.sleep(0.250) # Give the process some time to fill the queue
            if not queue.empty(): # If is not empty then go to stConnect
                self.state = "connected"
                self.stConnect()
                #threading.Thread(name="idle", target=self.stConnect).start()
                # I would like to run stConnect in a thread, but for now OK
        elif state == "connected":
            # Idealistically I would like that hitting the button again
            # would terminate the process, but for now is OK
            self.state = "idle"
            self.slave_process.terminate()
            self.stIdle()
            #threading.Thread(name="idle", target=self.stIdle).start()

    def write(self, queue):
        while True:
            print("write")
            queue.put("QUEUE")

Main()

我编辑了代码,将 process.run() 更改为 process.start() 现在它告诉我这个错误以及打开一个新的 tkinter 实例:

C:\Users\U4928\Documents\workspace\RawData>C:\Programs_RD\Python\Python36-32\python.exe test.py
acConnect
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Programs_RD\Python\Python36-32\lib\tkinter\__init__.py", line 1702, in __call__
    return self.func(*args)
  File "test.py", line 39, in btConnect
    self.slave_process.start()
  File "C:\Programs_RD\Python\Python36-32\lib\site-packages\multiprocess\process.py", line 112, in start
    self._popen = self._Popen(self)
  File "C:\Programs_RD\Python\Python36-32\lib\site-packages\multiprocess\context.py", line 223, in _Popen
    return _default_context.get_context().Process._Popen(process_obj)
  File "C:\Programs_RD\Python\Python36-32\lib\site-packages\multiprocess\context.py", line 322, in _Popen
    return Popen(process_obj)
  File "C:\Programs_RD\Python\Python36-32\lib\site-packages\multiprocess\popen_spawn_win32.py", line 65, in __init__
    reduction.dump(process_obj, to_child)
  File "C:\Programs_RD\Python\Python36-32\lib\site-packages\multiprocess\reduction.py", line 63, in dump
    ForkingPickler(file, protocol).dump(obj)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 437, in dump
    self.save(obj)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 549, in save
    self.save_reduce(obj=obj, *rv)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 662, in save_reduce
    save(state)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Programs_RD\Python\Python36-32\lib\site-packages\dill\_dill.py", line 893, in save_module_dict
    StockPickler.save_dict(pickler, obj)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 856, in save_dict
    self._batch_setitems(obj.items())
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 882, in _batch_setitems
    save(v)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Programs_RD\Python\Python36-32\lib\site-packages\dill\_dill.py", line 1069, in save_instancemethod0
    pickler.save_reduce(MethodType, (obj.__func__, obj.__self__), obj=obj)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 638, in save_reduce
    save(args)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 771, in save_tuple
    save(element)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 549, in save
    self.save_reduce(obj=obj, *rv)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 662, in save_reduce
    save(state)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Programs_RD\Python\Python36-32\lib\site-packages\dill\_dill.py", line 893, in save_module_dict
    StockPickler.save_dict(pickler, obj)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 856, in save_dict
    self._batch_setitems(obj.items())
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 882, in _batch_setitems
    save(v)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 549, in save
    self.save_reduce(obj=obj, *rv)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 662, in save_reduce
    save(state)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Programs_RD\Python\Python36-32\lib\site-packages\dill\_dill.py", line 893, in save_module_dict
    StockPickler.save_dict(pickler, obj)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 856, in save_dict
    self._batch_setitems(obj.items())
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 882, in _batch_setitems
    save(v)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Programs_RD\Python\Python36-32\lib\site-packages\dill\_dill.py", line 893, in save_module_dict
    StockPickler.save_dict(pickler, obj)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 856, in save_dict
    self._batch_setitems(obj.items())
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 887, in _batch_setitems
    save(v)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 549, in save
    self.save_reduce(obj=obj, *rv)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 662, in save_reduce
    save(state)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 504, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Programs_RD\Python\Python36-32\lib\site-packages\dill\_dill.py", line 893, in save_module_dict
    StockPickler.save_dict(pickler, obj)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 856, in save_dict
    self._batch_setitems(obj.items())
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 882, in _batch_setitems
    save(v)
  File "C:\Programs_RD\Python\Python36-32\lib\pickle.py", line 524, in save
    rv = reduce(self.proto)
TypeError: can't pickle _tkinter.tkapp objects

标签: pythonqueuemultiprocessing

解决方案


通过调用 start() 来启动一个进程,这将设置进程运行方法以在单独的进程中运行。

所以尝试替换self.slave_process.run()self.slave_process.start()

它在这里解释:https ://docs.python.org/3/library/multiprocessing.html?highlight=process#multiprocessing.Process


推荐阅读