Многопроцессорная обработка в блоках Python при запросе на запуск - PullRequest
0 голосов
/ 04 декабря 2018

Я разрабатываю программу, которая выполняет опрос, и мне нужно, чтобы опрос проводился в отдельном процессе по соображениям производительности.Программа довольно длинная, но мне удалось сократить ее до минимума, чтобы ее было легче понять.Это машина с двумя состояниями, одна бездействующая, а другая печатает значения, которые отдельный процесс поместил в очередь.

Итак, проблема в том, что при заказе многопроцессорного процесса на запуск все зависает.Только процесс работает как сумасшедший, и программа не реагирует.

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

1 Ответ

0 голосов
/ 04 декабря 2018

Процесс запускается вызовом start () для него, который настроит метод запуска процесса для запуска в отдельном процессе.

Поэтому попробуйте заменить: self.slave_process.run() на self.slave_process.start()

Это объясняется здесь: https://docs.python.org/3/library/multiprocessing.html?highlight=process#multiprocessing.Process

...