2009-12-11 17 views

cevap

59

Sana parçacığı başlamadan önce Queue.Queue örneğini ve parçacığının args biri olarak geçmesi öneririm. Ebeveyn, istediği zaman .get veya .get_nowait yapabilir.

Kuyruklar genellikle Python iplik senkronizasyonu ve iletişimi düzenlemek için en iyi yoldur: bunlar özünde evreli, ileti geçirme araçları konum - genel olarak çoklu görev düzenlemenin en iyi yolu -)

+2

'iplik bitmeden, bunu ne piton tarafından otomatik olarak yapılacaktır anlamına bir argument' olarak alınan sıraya sonucu .puts iyi çalışıyor gibi görünüyor? eğer değilse (tasarım ipucu olarak anılırsa) cevabın netleşmesini sağlayabilirsiniz. – n611x007

+3

Bunun için mevcut bir işlevi uzmanlaşmak çirkin; Kuyrukta, tek bir sonuç sorunu için gereksiz bir ek yük vardır. Daha açık ve etkin bir şekilde alt sınıf "threading.Thread" ve yeni run() yöntemi, sonucu "self.ret = ..." gibi öznitelik olarak kaydeder (Çok daha rahat bir şekilde, dönüş değerlerini/istisnalarını işleyen bir İş Parçasının alt sınıfı olur. Özel hedef işlevi.Gelişmiş "threading.Thread" kutusundan dışarı sunmak için uzatılmalıdır - eski davranış ile uyumlu olurdu "dönüş Yok".) – kxr

1

Python iş parçacığı modülünde, kilitlerle ilişkili durum nesneleri vardır. Bir yöntem acquire(), temel alınan yöntemden hangi değer döndürülürse döndürülür. Daha fazla bilgi için: bir argüman olarak alınan sıraya iplik bitmeden, bu .put s sonucu: Python Condition Objects

5

başka bir yaklaşım! iş parçacığına bir geriçağırım işlevini iletmektir. Bu, her zaman yeni iş parçacığından, üst öğeye değer döndürmek için basit, güvenli ve esnek bir yol sağlar.

# A sample implementation 

import threading 
import time 

class MyThread(threading.Thread): 
    def __init__(self, cb): 
     threading.Thread.__init__(self) 
     self.callback = cb 

    def run(self): 
     for i in range(10): 
      self.callback(i) 
      time.sleep(1) 


# test 

import sys 

def count(x): 
    print x 
    sys.stdout.flush() 

t = MyThread(count) 
t.start() 
+8

Buradaki sorun, geri arama hala çalışır Orijinal iş parçacığı yerine çocuk iş parçacığı. – babbageclunk

+0

@wilberforce, hangi sorunlara neden olabileceğini açıklayabilir misiniz? –

+4

Tamam. Geri arama, iş parçacığı çalışırken üst iş parçacığının da yazdığı bir günlük dosyasına yazıyorsa bu örnek olur. Geri arama, çocuk iş parçacığı içinde çalıştığı için, aynı anda gerçekleşen ve çarpışan iki yazma riski vardır. Bozuk ya da araya sokulmuş çıktının alınması ya da günlüğe kaydetme çerçevesinin bazı dahili defter tutma işlemleri yapması durumunda bir çarpışma olabilir. Bir iş parçacığı güvenli kuyruğu kullanmak ve bir iş parçacığına sahip olmak tüm yazıyı bunu engeller. Bu tür problemler, deterministik olmadıkları için çirkin olabilirler - sadece üretimde ortaya çıkabilirler ve çoğaltılamazlar. – babbageclunk

12

tamamlamak iplik beklemek() katılmak çağırarak olsaydı, sadece Konu örneğine kendisine sonucunu eklemenizi ve daha sonra katılmak() döndükten sonra ana iş parçacığı çağırın.

Diğer taraftan, iş parçacığının yapıldığını ve sonucun kullanılabilir olduğunu nasıl anlamaya niyetlendiğinizi bize söylemezsiniz. Eğer bunu zaten yapmanın bir yolu varsa, muhtemelen (ve eğer bize söyleseydiniz) sonuçları elde etmenin en iyi yoluna işaret edecektir.

+0

* sonucu yalnızca Thread örneğinin kendisine ekleyebilirsiniz. Thread ismini, hedefin bu örnekle ilişkilendirebilmesi için, çalıştığı hedefe nasıl geçirirsiniz? –

+1

Piotr Dobrogost, eğer alt sınıfın alt sınıfını oluşturmuyorsanız, örneğiniz için iş parçacığı sonuna kadar threading.current_thread() öğesini kullanabilirsiniz. Ben buna çirkin denirdim, ama Alex'in yaklaşımı her zaman daha zarifti. Bu, bazı durumlarda sadece daha uygun. –

+3

Eğer join() 'sadece çağrılan yöntem geri dönüşünü döndürürse ... güzel olur, bunun yerine" Yok "u döndürür. – ArtOfWarfare

10

Bir Kuyruk örneğini parametre olarak iletmeniz gerekir, ardından döndürme nesnesini sıraya sığdırmalısınız. Verdiğiniz değeri, queue.get() ile gönderebilirsiniz.

Örnek: birden çok iş parçacığı için

queue = Queue.Queue() 
thread_ = threading.Thread(
       target=target_method, 
       name="Thread1", 
       args=[params, queue], 
       ) 
thread_.start() 
thread_.join() 
queue.get() 

def target_method(self, params, queue): 
""" 
Some operations right here 
""" 
your_return = "Whatever your object is" 
queue.put(your_return) 

Kullanım:

#Start all threads in thread pool 
    for thread in pool: 
     thread.start() 
     response = queue.get() 
     thread_results.append(response) 

#Kill all threads 
    for thread in pool: 
     thread.join() 

bu uygulamayı kullanır ve bu benim için iyi çalışıyor. Keşke yapmanı diliyorum.

+1

Thread_.start() 'ı kaçırmıyor musunuz?Tabii – sadmicrowave

+1

Ben sadece burada çizgiyi koymak kaçırmak iplik başlamak :) haber için teşekkürler. –

+0

Birden fazla iş parçacığınız varsa nasıl görünürdü? que.get() sadece benim için bir iş parçacığının sonucunu döndürür? – ABros

6

Kullanım lambda hedef iplik fonksiyonunu sarın ve bir kuyruğunu kullanarak ana konuya geri dönüş değerini geçmesi. (Orijinal hedef fonksiyonu ekstra kuyruk parametresi olmadan değişmez.)

örnek kod:

import threading 
import queue 
def dosomething(param): 
    return param * 2 
que = queue.Queue() 
thr = threading.Thread(target = lambda q, arg : q.put(dosomething(arg)), args = (que, 2)) 
thr.start() 
thr.join() 
while not que.empty(): 
    print(que.get()) 

Çıktı:

4 
2

POC: Sen queue senkronize kullanabilirsiniz

import random 
import threading 

class myThread(threading.Thread): 
    def __init__(self, arr): 
     threading.Thread.__init__(self) 
     self.arr = arr 
     self.ret = None 

    def run(self): 
     self.myJob(self.arr) 

    def join(self): 
     threading.Thread.join(self) 
     return self.ret 

    def myJob(self, arr): 
     self.ret = sorted(self.arr) 
     return 

#Call the main method if run from the command line. 
if __name__ == '__main__': 
    N = 100 

    arr = [ random.randint(0, 100) for x in range(N) ] 
    th = myThread(arr) 
    th.start() 
    sortedArr = th.join() 

    print "arr2: ", sortedArr 
3

modülü.

def check_infos(user_id, queue): 
    result = send_data(user_id) 
    queue.put(result) 

Şimdi böyle verilerinizi alabilirsiniz:

import queue, threading 
queued_request = queue.Queue() 
check_infos_thread = threading.Thread(target=check_infos, args=(user_id, queued_request)) 
check_infos_thread.start() 
final_result = queued_request.get() 
6

Sürpriz kimse bunu sen tekini söz olduğum
Eğer bilinen bir kimliğe sahip veritabanından bir kullanıcı bilgilerinizi kontrol gerekir düşünün Belki de bunun habersiz olduğum başlıca sorunları vardır.

+1

Bu mükemmel çalışıyor! Varsa, bu yaklaşımla eksik olan şeyler hakkında bazı fikirleri duymak isterim. –

+0

çalışır. Sadece var olan bir işlevi - ve bu çok kafa karıştırıcı şeyleri (okunabilirlik) - uzmanlaşmak çirkin - 1. cevap hakkındaki yorumu görün. – kxr

+0

Çok iş parçacığına ne dersin? – backslash112

0

Aşağıdaki sarma işlevi, varolan bir işlevi saracak ve her ikisini de işaret eden bir nesneyi döndürecektir (böylece start(), join(), vb .'yi arayabilmeniz için) ve aynı zamanda nihai dönüş değerini görüntüleme/görüntüleme.

def threadwrap(func,args,kwargs): 
    class res(object): result=None 
    def inner(*args,**kwargs): 
    res.result=func(*args,**kwargs) 
    import threading 
    t = threading.Thread(target=inner,args=args,kwargs=kwargs) 
    res.thread=t 
    return res 

def myFun(v,debug=False): 
    import time 
    if debug: print "Debug mode ON" 
    time.sleep(5) 
    return v*2 

x=threadwrap(myFun,[11],{"debug":True}) 
x.thread.start() 
x.thread.join() 
print x.result 

Tamam görünüyor ve threading.Thread sınıf kolayca işlevselliği bu tür (*) uzatılabilir görünüyor, bu yüzden zaten orada değil neden merak ediyorum. Yukarıdaki yöntemle bir kusur var mı?

(*) Bu soru için husanu'nun cevabının tam olarak threading.Thread alt sınıfını, join() döndürme değerini verdiği bir sürümle sonuçlandığını unutmayın.

1

jcomeau_ictx'ın önerisine dayanmaktadır. Karşılaştığım en basit olanı. Buradaki gereksinim, sunucuda çalışan üç farklı işlemden çıkış durumu statüsünü almak ve üçünün de başarılı olması durumunda başka bir komut dosyasını tetiklemekti. Bu

class myThread(threading.Thread): 
     def __init__(self,threadID,pipePath,resDict): 
      threading.Thread.__init__(self) 
      self.threadID=threadID 
      self.pipePath=pipePath 
      self.resDict=resDict 

     def run(self): 
      print "Starting thread %s " % (self.threadID) 
      if not os.path.exists(self.pipePath): 
      os.mkfifo(self.pipePath) 
      pipe_fd = os.open(self.pipePath, os.O_RDWR | os.O_NONBLOCK) 
      with os.fdopen(pipe_fd) as pipe: 
       while True: 
        try: 
        message = pipe.read() 
        if message: 
         print "Received: '%s'" % message 
         self.resDict['success']=message 
         break 
        except: 
         pass 

    tResSer={'success':'0'} 
    tResWeb={'success':'0'} 
    tResUisvc={'success':'0'} 


    threads = [] 

    pipePathSer='/tmp/path1' 
    pipePathWeb='/tmp/path2' 
    pipePathUisvc='/tmp/path3' 

    th1=myThread(1,pipePathSer,tResSer) 
    th2=myThread(2,pipePathWeb,tResWeb) 
    th3=myThread(3,pipePathUisvc,tResUisvc) 

    th1.start() 
    th2.start() 
    th3.start() 

    threads.append(th1) 
    threads.append(th2) 
    threads.append(th3) 

    for t in threads: 
     print t.join() 

    print "Res: tResSer %s tResWeb %s tResUisvc %s" % (tResSer,tResWeb,tResUisvc) 
    # The above statement prints updated values which can then be further processed 
İlgili konular