2010-02-11 71 views
9

我需要編寫運行兩個線程一個簡單的應用程序: - 線程1:運行在一定的時間週期,假設每1分鐘 - 線程2:只是一個「正常的」,而真正的循環,它「東西」扭曲的線程...如何正確使用它們?

如果不能在一定的時間間隔運行的要求我會在扭曲沒有看過,而是簡單的睡眠(60)不夠好和施工,如:

l = task.LoopingCall(timed_thread) 
l.start(60.0) 
reactor.run() 

看起來很簡單的實現我想要的東西有。

現在,我該如何'正確地'添加另一個線程?

在這裏我看到兩個選項:

  • 使用線程庫和運行兩個「蟒蛇線程的一個執行我的while循環,和其他正在運行的reactor.run()。但谷歌似乎反對這種方法,並建議使用扭絞線程
  • 使用扭曲線程。這是我試過的,但不知何故,這對我來說看起來有點笨拙。

這就是我想出了:

def timed_thread(): 
    print 'i will be called every 1 minute' 
    return 

def normal_thread(): 
    print 'this is a normal thread' 
    time.sleep(30) 
    return 

l = task.LoopingCall(timed_thread) 
l.start(60.0) 
reactor.callInThread(normal_thread) 
reactor.run() 

,似乎工作,但!我無法停止該應用程序。如果我按下^ C它不會做任何事情(沒有'callInThread'它只會停止,因爲你會期望它)。^Z炸彈出殼,如果我然後'殺死%1'似乎殺死進程(殼報告),但'正常'線程繼續運行。殺PID不會消除它,唯一的治療方法是殺死-9。真奇怪。

所以。我究竟做錯了什麼?在扭曲中實現兩個線程是否正確?我不應該打擾扭曲?還有哪些其他「標準」替代方案可以實現定時呼叫? ('標準'我的意思是我可以easy_install或yum安裝它們,我不想開始下載並使用隨機網頁中的一些隨機腳本)。

+0

您可以非常小心地使用扭曲的線程(以及一般的python)。你的「主」在做什麼?一個頻繁使用的情況是作爲協議客戶端/服務器,請求或監聽請求。反應堆將處理這些請求,並假設它們是非阻塞的,將能夠在特定時間間隔內啓動特定功能。 – MattH 2010-02-11 09:39:40

+0

線程的危險在於,如果您不小心,一個線程可能會在數據被另一個線程使用時修改數據,從而導致不可預知的行爲。 – MattH 2010-02-11 09:44:32

+0

所有的'main'只是爲了激發這兩個線程(事實上它只有4行,你可以在示例中看到),但這兩個函數都有點複雜,但在處理方面沒有什麼不尋常的地方,只是檢查它,但這並不重要)。這兩個線程不共享任何數據btw – rytis 2010-02-11 09:45:10

回答

2

假設你的主要是相對非阻塞:

import random 
from twisted.internet import task 

class MyProcess: 
    def __init__(self): 
    self.stats = [] 
    self.lp = None 
    def myloopingCall(self): 
    print "I have %s stats" % len(self.stats) 
    def myMainFunction(self,reactor): 
    self.stats.append(random.random()) 
    reactor.callLater(0,self.myMainFunction,reactor) 
    def start(self,reactor): 
    self.lp = task.LoopingCall(self.myloopingCall) 
    self.lp.start(2) 
    reactor.callLater(0,self.myMainFunction,reactor) 
    def stop(self): 
    if self.lp is not None: 
     self.lp.stop() 
    print "I'm done" 

if __name__ == '__main__': 
    myproc = MyProcess() 
    from twisted.internet import reactor 
    reactor.callWhenRunning(myproc.start,reactor) 
    reactor.addSystemEventTrigger('during','shutdown',myproc.stop) 
    reactor.callLater(10,reactor.stop) 
    reactor.run() 
 
$ python bleh.py 
I have 0 stats 
I have 33375 stats 
I have 66786 stats 
I have 100254 stats 
I have 133625 stats 
I'm done 
+0

這不使用線程。 – MattH 2010-02-11 10:12:37

+0

你的意思是這不使用python線程。我懷疑它仍然是通過扭曲的lib進行線程化的? – rytis 2010-02-11 10:44:56

+1

不,這是單線程的。如果你告訴它,Twisted只使用線程。閱讀http://twistedmatrix.com/documents/current/core/howto/threading.html – MattH 2010-02-11 11:17:02

5

你沒有解釋爲什麼你真正需要的線程在這裏。如果你有,我可能已經能夠解釋你爲什麼不需要需要它們。 ;)

除此之外,我可以確認你對事物的基本理解是正確的。然而,我可以清楚的一個可能的誤解是「蟒蛇線」和「扭曲線」彼此完全不同。他們不是。 Python提供了一個線程庫。所有Twisted的線程API都是通過Python的線程庫實現的。只有API是不同的。

只要關機,你有兩個選擇。

  • 直接使用Python的線程API啓動永久運行線程並使線程成爲守護進程。即使守護程序線程仍在運行,您的進程也可以退出。這個解決方案的一個可能的問題是某些版本的Python在守護線程中存在問題,這將導致關機時崩潰。
  • 使用Twisted的API或stdlib線程API創建線程,但也使用reactor.addSystemEventTrigger('before', 'shutdown', f)添加Twisted關閉鉤子。在該鉤子中,與工作線程通信並告訴它關閉。例如,您可以在Twisted線程和您的工作線程之間共享一個threading.Event,並擁有鉤子set它。工作線程可以定期檢查它是否已經設置,並在它注意到它已經退出時退出。除了沒有崩潰之外,這比守護進程線程提供了另一個優勢 - 它可以讓您在進程退出之前在工作線程中運行一些清理或終止代碼。
+0

+1嗨JP,感謝您的協助。我不認爲我能完成扭曲的支持者的任務。 – MattH 2010-02-11 14:15:02

+0

np Matt。 :)我認爲你的回答非常好,除了處理「可能需要一分多鐘」才能完成的神祕案例。如果我們知道這些案例是什麼,我們可能會提出一種方法來調整您的解決方案來處理它們,並且實際上消除線程的使用。 – 2010-02-11 18:29:25

+0

請參閱Matt的回答評論中的描述。很難解釋,我需要處理各種情況。以此爲例(這與現實非常接近):t1甚至可以讀取來自1mil日曆的條目,並將計劃在那一分鐘發生的事件放入數據庫表中。而已。 t2(t3,4,...)在表格中爬行並執行指令。沒有必要要求處理該事件的確切時間,只是需要在該時刻進入隊列。所以t2(3,4,...)一直在世界上,但t1受到限制。 – rytis 2010-02-11 23:16:35