2010-05-21 4 views
17

별도의 스레드에서 실행하고자하는 일련의 '작업'이 있습니다. 작업은 별도의 모듈에 의해 수행됩니다. 각각은 업무 처리를위한 비즈니스 로직을 포함합니다.파이썬에서 스레드 생성하기

여러 개의 태스크가 주어지면 다음과 같이 각 모듈에 대해 새 스레드를 생성하고 싶습니다.

from foobar import alice, bob charles 
data = getWorkData() 
# these are enums (which I just found Python doesn't support natively) :(
tasks = (alice, bob, charles) 

for task in tasks 
    # Ok, just found out Python doesn't have a switch - @#$%! 
    # yet another thing I'll need help with then ... 
    switch 
    case alice: 
     #spawn thread here - how ? 
     alice.spawnWorker(data) 

추측을위한 상금 나는 여전히 C++로 생각하고 있습니다. Pythonic 'enums'및 'switch'를 사용하여 Pythonic 방식으로 이것을 작성하고 새 스레드에서 모듈을 실행할 수있게하려면 어떻게해야합니까?

분명히 모듈에는 모두 Plugin이라는 ABC (추상 기본 클래스)에서 파생 된 클래스가 있습니다. spawnWorker() 메서드는 Plugin 인터페이스에서 선언되고 다양한 모듈에 구현 된 클래스에서 정의됩니다.

아마도이 모든 작업을 수행하는 데 더 좋은 (Pythonic) 방법이있을 수 있습니다. 나는 알고에 관심이있을 것

[편집]

난 그냥 더 봇을 읽어 봤는데 적어도이 아닌 의미에서 (파이썬은 진정한 의미에서 스레딩을 구현하지 않습니다 보인다 C++ 프로그래머는 생각할 것입니다.) 어쨌든 저를위한 쇼 스토퍼가 아닙니다. 각각의 작업은 상당히 시간이 많이 걸리고 또 다른 작업이 완료 될 때까지 하나의 작업을 시작하고 싶지 않습니다. 스레딩을 사용하는 이유입니다. 타임 슬라이싱은별로 신경 쓰지 않습니다. 파이썬은 동시에 (또는 잠시 후에) 거의 모두 시작될 때 파이썬이 원하는만큼 트레드를 타임 슬립 할 수 있습니다.

저는 비슷한 질문에 대한 답변을 여기에서 보았습니다.

import threading 
class Foo (threading.Thread): 
    def __init__(self,x): 
     self.__x = x 
     threading.Thread.__init__(self) 
    def run (self): 
      print str(self.__x) 

for x in xrange(20): 
    Foo(x).start() 

을 내 ABC 플러그인이를 사용하여 생각하고 다음과 같이

사용자는 스레딩에 대한 간단한 클래스를 제공합니다. 내 질문은 실제 작업 (예 : 비즈니스 로직)이 완료된 곳에서 코드를 어디에 넣는가입니다. 나는 이것이 Foo 클래스의 run() 메소드에 있다고 가정한다. (당연한 질문이지만, 나는 어떤 가정을하고 싶지 않다.)

오른쪽 트랙 또는 결함에 대한 내 생각인가 (결함이 있다면? - 내가 놓친 것)

+0

switch-case 대신 적절한 다형성 (ABC 상속 또는 오리 입력)을 사용하지 않는 이유는 무엇입니까? – Santa

+0

@Santa : 좋은 지적. 어떻게 C++에서 (다형성) 그것을했을 것입니다. 그러나 파이썬이이를 지원하는지에 대해서는 잘 모르겠습니다. – morpheous

+0

@morpheous 전통적인 상속 기반 다형성에 더하여, 파이썬은 다형성에 대한보다 역동적 인 접근법을 지원하며, 가장 중요한 것은 오리 타이핑입니다. – Santa

답변

24

switch-case 대신 적절한 다형성을 사용하는 것이 어떻습니까? 예를 들어, 파이썬에서 오리 입력으로 할 수있는 무슨 :

에서 말하자면, alice.py :

def do_stuff(data): 
    print 'alice does stuff with %s' % data 

에서 말하자면, bob.py : 클라이언트 코드에서 다음

def do_stuff(data): 
    print 'bob does stuff with %s' % data 

, 말하자면, main.py :

import threading 
import alice, bob 

def get_work_data(): 
    return 'data' 

def main(): 
    tasks = [alice.do_stuff, bob.do_stuff] 
    data = get_work_data() 
    for task in tasks: 
     t = threading.Thread(target=task, args=(data,)) 
     t.start() 

내가 명확히 할 필요가있는 경우 알려 주시기 바랍니다.

+0

+1 코드가 멋지고 간단합니다. 그러나 생성 된 스레드에 데이터를 전달하지 않습니다. 코드를 수정하여 데이터가 어떻게 전달되는지 보여줄 수 있습니까? 스폰 된 스레드 (내 의사 코드와 같은)?tx – morpheous

+6

'data'가 변경 될 수 있다면, 각 쓰레드에 복사본을 전달하거나 잠금 객체를 전달하기를 원할 것입니다 (http://docs.python.org/library/threading.html # lock-objects). – tgray

1

파이썬은 객체로 기능을 보유 할 수 있습니다. 스위치 부족에 대한 한계를 극복하기 위해 다음을 제안 할 수 있습니다.

case_alice = lambda data : alice.spawnWorker(data) 

my_dict[alice] = case_alice 

"사례"문을 유지하기위한 사전을 구성합니다.

나를 더욱 그것을 보자

data = getWorkData() 
case_alice = lambda d : alice.spawnWorker(d) 
case_bob = lambda d : bob.spawnWorker(d) 
case_charles = lambda d : charles.spawnWorker(d) 

switch = { alice : case_alice, bob : case_bob, charles : case_charles } 
spawn = lambda person : switch[ person ](data) 
[ spawn(item) for item in (alice, bob, charles)] 
+0

@wheaties : Pythonic 코드에 +1 (여전히 내가 거기에있는 모든 것을 이해하는지 확인하기 위해 읽음). 멀티 프로세싱 모듈을 사용하여 스레드 (또는 프로세스 - 실제로는 문제가 아님)를 생성하는 방법과 함께 인형을 조금 확장 할 수 있습니까? – morpheous

+4

'람다'는 전혀 필요하지 않습니다. 간단히'my_dict [alice] = alice.spawnWorker' 그리고'[item in ...]에 대한 switch [item] (data)' –

+0

@morpheous 멀티 프로세싱 라이브러리에 대한 경험이 없습니다. @ 토마스 Wouters 당신은 절대적으로 옳습니다. 그러나 나는 그것들을 그대로 두는 것이 일류 대상으로서의 기능을 이해하는데 도움이된다고 생각합니다. 내가 처음 배웠을 때, 람다를 보는 것은 나에게 그런 것을 상기시켰다. – wheaties

2

순차적으로 실행

from foobar import alice, bob charles 

for fct in (alice, bob charles): 
    fct() 

병렬 실행

from threading import Thread 
from foobar import alice, bob charles 

for fct in (alice, bob charles): 
    Thread(target=fct).start() 
+0

스레드는'start'가 아닌'run' 메서드를 가지고 있습니다. – nkrkv

+1

@nailxx'run' 메서드는 스레드의 실행에 필요한 작업을 정의하는 곳입니다. 'start' 메쏘드는 별도의 실행 스레드에서'run'을하기 위해 스레드 객체에 보내야하는 메소드입니다. 그렇지 않으면, 당신은 현재 쓰레드에서 실행하고 있기 때문에,'Thread'가 시작하도록 정의하는 목적을 무효로합니다. – Santa

+0

@nailxx, 게시물의 댓글에 설명 된 문서에 대한 링크를 달았습니다. – tgray

4
import threading 
from foobar import alice, bob, charles 

data = get_work_data() # names_in_pep8 are more Pythonic than camelCased 

for mod in [alice, bob, charles]: 
    # mod is an object that represent a module 
    worker = getattr(mod, 'do_work') 
    # worker now is a reference to the function like alice.do_work 
    t = threading.Thread(target=worker, args=[data]) 
    # uncomment following line if you don't want to block the program 
    # until thread finishes on termination 
    #t.daemon = True 
    t.start() 

해당 개월의 do_work 기능에 논리를 넣어 쥴.

+0

좋은 답변이지만, 마지막 줄은't.start()'여야합니다. – tgray

+0

http://docs.python.org/library/threading.html#thread-objects – tgray

+0

+1 모듈에 대해 직접 반복 할 수 있으므로이 대답이 정말 마음에 듭니다. 너무 차가워 요.) 대답이 '예'인 경우 각 모듈에 'do_work'라는 함수가있는 한 위의 코드는 스레드를 생성하고 별도의 스레드에있는 각 모듈에서 do_work() 함수를 실행합니다. ?). 최종 메소드 호출이 start()가되어야하는 것처럼 보입니까? – morpheous