2013-05-03 2 views
-2

мне нужна помощь с проектом питона:Как запустить метод Python в качестве подпроцесса?

Пример:

class MyFrame(wx.Frame): 
    def __init__(self, parent, title):  
     super(MyFrame, self).__init__(parent, title=title, size=(330, 300)) 
     self.InitUI() 
     self.Centre() 
     self.Show() 

    def InitUI(self): 
     """ 
     Subprocess 
     """ 
     subprocess.execMethodFromClass(self , 'Connection' , args1 , args2 , ...) 

    def Connection(self): 
     self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.connection.connect(('192.0.1.135' , 3345)) 
     while True: 
      data = self.connection.recv(1024) 
      if not data: 
       break 
      else: 
       print data 

Показать:

subprocess.execMethodFromClass(self , 'Connection' , args1 , args2 , ...) 

спасибо!

+2

, пожалуйста, приложите больше усилий, чтобы объяснить вашу проблему! – Moj

+1

, вероятно, вы хотите запустить 'Connection' в фоновом * потоке * (не подпроцессе) и сообщить результаты в основной поток (GUI), используя' wx.CallAfter() '(см. [Long Running Tasks wiki] (http: // wiki.wxpython.org/LongRunningTasks)). – jfs

ответ

2

Как говорит дружественный dogcow, чтобы запустить функцию в дочернем процессе, все, что вам нужно сделать используется multiprocessing.Process:

p = multiprocessing.Process(target=f, args=('bob',)) 
p.start() 
p.join() 

Конечно, вы, вероятно, захотите повесить на p и join позже в большинстве случаев использования в реальных условиях. Вы, очевидно, не получаете никакого параллелизма, создавая новый процесс, чтобы заставить ваш основной процесс сидеть и ждать.

Таким образом, в вашем случае, это просто:

p = multiprocessing.Process(target=self.Connection, args=(args1, args2)) 

Но это, вероятно, не будет работать в вашем случае, потому что вы пытаетесь вызвать метод текущего self объекта.

Прежде всего, в зависимости от вашей платформы и версии Python, multiprocessing может передать связанный метод self.Connection ребенку, протравив его и отправив его по трубе. Это включает в себя травление экземпляра self, а также метод. Таким образом, он будет работать, только если MyFrame объекты разборчивы. И я уверен, что wx.Frame не может быть маринован.

И даже если вы сделать получить self объект для ребенка, это, очевидно, будет копия, а не общий случай. Итак, когда метод Connection дочернего процесса устанавливает self.connection = …, это не повлияет на исходный родительский процесс self.

Еще хуже, если вы попытаетесь позвонить любым wx.Frame методам. Даже если все материалы Python работали, на большинстве платформ попытка изменить ресурсы GUI, такие как окна из неправильного процесса, не будет работать.

Единственные виды объектов, которые вы действительно можете разделить, - это виды, которые вы можете поместить в multiprocessing.Value или multiprocessing.sharedctypes.


Обойти это факторизовать код, который вы хотите childify в отдельную изолированную функцию, что акции как можно меньше (в идеале ничего, или почти ничего, кроме Queue or Pipe) с родителем.

Для примера, это легко:

class Client(object): 
    def connect_and_fetch(self): 
     self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.connection.connect(('192.0.1.135' , 3345)) 
     while True: 
      data = self.connection.recv(1024) 
      if not data: 
       break 
      else: 
       print data 

def do_client(): 
    client = Client() 
    connect_and_fetch() 

class MyFrame(wx.Frame): 
    # ... 
    def Connection(self): 
     self.child = multiprocessing.Process(target=do_client) 
     self.child.start() 
    # and now put a self.child.join() somewhere 

В самом деле, вам даже не нужен класс вообще здесь, потому что только у вас есть использование для self для хранения переменной, которая может просто так же легко быть локальным. Но я предполагаю, что в вашей реальной программе, есть немного больше состояния, чем это.

Есть интересный (если немного устаревший) пример на wiki wxpython, который называется MultiProcessing, который выглядит так, как будто он делает большую часть того, что вы хотите, и многое другое. (Это с помощью classmethod для дочернего процесса, а не отдельной функции по какой-то причине, а также с использованием синтаксиса старого стиля для него, потому что это старое, но, надеюсь, это все-таки полезно.)


Если вы используете wx для вашего графического интерфейса вы можете захотеть использовать свои механизмы межпроцессного взаимодействия вместо собственных Python. Хотя это сложнее и менее pythonic в общем случае, когда вы пытаетесь интегрировать дочерний процесс и его канал связи в свой основной цикл событий, почему бы не позволить wx позаботиться об этом?

Альтернативой создать поток ждать на дочернем процессе и/или любой другой Pipe или Queue вы даете его, а затем создать и разместить wx.Event сек в основной поток.


* Большинство, не все. Например, если f временно использует большую часть памяти, ее запуск в дочернем процессе означает, что вы быстро освободите эту память для ОС. Или, если он вызывает плохо написанный сторонний/наследственный/любой код, который имеет неприятные и плохо документированные глобальные побочные эффекты, вы изолированы от этих побочных эффектов. И так далее.

1

http://docs.python.org/dev/library/multiprocessing.html От:

from multiprocessing import Process 

def f(name): 
    print('hello', name) 

if __name__ == '__main__': 
    p = Process(target=f, args=('bob',)) 
    p.start() 
    p.join() 
+0

Но он хочет запустить метод на 'self', а не на уровне модуля. Я не думаю, что новичок может понять, как добраться отсюда туда. Тем более, что в его случае это не сработает, даже если он это выяснит. – abarnert

1

Вы не можете. Вы используете подпроцесс для вызова другого приложения или скрипта для запуска в отдельном процессе.

Если вам нужно запустить какой-то длительный процесс, посмотрите на потоки или модуль многопроцессорности. Вот некоторые ссылки:

Смежные вопросы