wxPython неблокирующая многопоточность GUI и многопроцессорность?

Python 2.7.3 x64 wxPython 2.8 x64

Я читал немало о потоке Python и многопроцессорности, особенно о некоторых статьях Дуга Хеллмана, которые очень помогли. Тем не менее, я запутался в одном ...

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

Если я попытаюсь выполнить многопроцессорную обработку напрямую без первой многопоточности, мой графический интерфейс по-прежнему блокируется до тех пор, пока не будет завершена многопроцессорная работа. Это работает как задумано, или я упускаю что-то фундаментальное в модуле многопроцессорности?

Если нужны примеры, я могу их предоставить.

Спасибо,

-RMWChaos

Пример был запрошен ...

Предполагая, что onProcess () запускается кнопкой в графическом интерфейсе, это блокирует графический интерфейс ...

import time
import multiprocessing as mp

def myWorker(a, b):
    time.sleep(0.1)
    print '{} * {} = {}'.format(a, b, a*b)

def onProcess(event):
    jobs = mp.cpu_count() * 2
    a = 5
    b = 10

    for job in range(jobs):
        mp.Process(target = myWorker, args = (a, b,)).start()

Хотя это не ...

import time
import multiprocessing as mp
import threading as th

def myWorker(a, b):
    time.sleep(0.1)
    print '{} * {} = {}'.format(a, b, a*b)

def onProcess(event):
    a = 5
    b = 10
    th.Thread(target = myThread, args = [a, b,]).start()

def myThread(a, b):
    jobs = mp.cpu_count() * 2

    for job in range(jobs):
        mp.Process(target = myWorker, args = (a, b,)).start()
 Amr07 июн. 2012 г., 18:05
Может быть, вы должны добавить небольшой пример, который описывает вашу проблему.

Ответы на вопрос(2)

и многопроцессорность работает нормально, ничего не заблокировано:

import time
import multiprocessing as mp
import wx


def myWorker(a, b):
    time.sleep(10)
    print '{} * {} = {}'.format(a, b, a*b)

def onProcess(event):
    jobs = mp.cpu_count() * 2
    a = 5
    b = 10

    for job in range(jobs):
        mp.Process(target = myWorker, args = (a, b,)).start()

def onGUI(event):
    print 'GUI is not blocked'

class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
       wx.Frame.__init__(self, parent, id, title)
       buttons = []
       panel = wx.Panel(self, wx.ID_ANY)
       sizer = wx.BoxSizer(wx.VERTICAL)
       gui_proc_btn = wx.Button(panel, wx.ID_ANY, 'GUI Process')
       other_proc_btn = wx.Button(panel, wx.ID_ANY, 'Other process')

       gui_proc_btn.Bind(wx.EVT_BUTTON, onGUI)
       sizer.Add(gui_proc_btn, 0, wx.ALL, 5)
       other_proc_btn.Bind(wx.EVT_BUTTON, onProcess)
       sizer.Add(other_proc_btn, 0, wx.ALL, 5)
       panel.SetSizer(sizer)

class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None, -1, 'test.py')
        frame.Show(True)
        self.SetTopWindow(frame)
        return True

if __name__ == '__main__':

    app = MyApp(0)
    app.MainLoop()

Запустите это из командной строки, нажмите вторую кнопку (это используетmultiprocessing по твоей функции, и я увеличил время сна), а затем нажми первую кнопку. Вы должны заметить, что при нажатии первой кнопки генерируется выходной сигнал, поэтому программа не блокируется.

 07 июн. 2012 г., 22:23
После последнего редактирования я попытался запустить тестовую программу в Windows, и она работает правильно.
 07 июн. 2012 г., 20:41
Ой, мой плохой. Глядя на многопроцессорностьdocumentation добавлениеif __name__ == '__main__' требуется на Windows, попробуйте запустить код сейчас.
 RMWChaos07 июн. 2012 г., 20:28
Выходные данные будут сгенерированы, но попытайтесь переместить графический интерфейс во время выполнения фоновых процессов mp, и вы получите «Not Responding» сообщение - хотя бы в винде. На самом деле, с вашим кодом, приведенным выше, он породил множество новых графических интерфейсов, и ничего не будет выводиться на консоль, пока я не закрою их все. Такое поведение, скорее всего, зависит от ОС, учитывая то, как Windows обрабатывает многопроцессорность; поэтому вы можете увидеть другие результаты, если вы работаете в Linux или что-то в этом роде. Спасибо!
 07 июн. 2012 г., 20:33
Да, я нахожусь на Linux. В Windows нет разветвлений, поэтому многопроцессорная обработка пытается скопировать всю программу в память, возможно, поэтому в итоге у вас есть несколько окон.

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

Мультиобработка, с другой стороны, порождает новый процесс на уровне ОС. Этот новый процесс может выполняться параллельно с уже существующим процессом, но он не разделяет пространство памяти с программой, которая его породила. Это более полезно, когда код, который вы хотите ускорить, не связан с вводом-выводом, а требует значительных вычислительных ресурсов процессора.

Для графического интерфейса вы в основном хотите использовать многопоточность для различных частей графического интерфейса, чтобы запуск чего-либо в одной части графического интерфейса не блокировал весь графический интерфейс пользователя до тех пор, пока эта обработка не закончится.

Без кода трудно сказать, но я считаю, что вам не нужно особенно запускать процесс в новом потоке, а просто обрабатывать этот поток. Однако, если этот поток должен обрабатывать интенсивный вычислительный тип обработки, в отличие от большого количества операций ввода-вывода, вы можете запустить процесс для обработки этого.

Я считаю, что большая часть вашей проблемы заключается в неправильном понимании многопоточности против многопоточности.

 RMWChaos07 июн. 2012 г., 19:26
Хороший совет. Поэтому я предполагаю, что это означает использование чего-то вроде Queue () для помещения результатов из порожденного потока и процессов, а из основного потока - Queue.get () для обновления GUI.
 07 июн. 2012 г., 18:25
То, что вы ищете, это многопоточность. Создайте новый поток для обработки события, и это должно решить проблему блокировки остальной части графического интерфейса. Кроме того, вы можете захотеть создать процесс для обработки внутри потока, но это больше зависит от дизайна и проблемы.
 RMWChaos07 июн. 2012 г., 18:23
Я думаю, что это отвечает на вопрос. По сути, я хочу, чтобы процессы, требующие большого объема вычислений и ввода-вывода, выполнялись в фоновом режиме, не блокируя графический интерфейс. Это говорит мне о том, что мне нужно выполнять как многопоточность, чтобы графический интерфейс не был заблокирован, так и многопроцессорность, чтобы разделить рабочую нагрузку между несколькими ядрами.
 RMWChaos07 июн. 2012 г., 18:28
Более или менее похож на второй пример, который я привел выше?
 07 июн. 2012 г., 18:46
В самом деле. Будьте осторожны, когда дело доходит до того, что вы делаете в порожденном потоке и обрабатываете по отношению к графическому интерфейсу. Обязательно посмотрите несколько примеров того, как сохранить ваши обновления потока графического интерфейса безопасными. Я не уверен, как именно работает wxPython, но, как правило, вы можете столкнуться с проблемами, если попытаетесь обновить графический интерфейс пользователя, кроме основного потока интерфейса.

Ваш ответ на вопрос