2012-01-14 69 views
2

我希望對處理「第一個」延遲的最佳方式進行一些說明,即不僅僅是將回調和errback添加到返回延遲的現有Twisted方法,但最好的方法創建那些原始延期。Python扭曲推遲:需要說明

舉一個具體的例子,這裏有同樣的方法的2個版本: 它只是計數線在一些相當大的文本文件的數量,以及用作deferreds鏈中的起點

方法1: 這個不太好,因爲延遲是由reactor.callLater方法直接觸發的。

def get_line_count(self): 
    deferred = defer.Deferred() 

    def count_lines(result): 
     try: 
      print_file = file(self.print_file_path, "r") 
      self.line_count = sum(1 for line in print_file) 
      print_file.close() 
      return self.line_count 
     except Exception as inst: 
      raise InvalidFile() 

    deferred.addCallback(count_lines) 
    reactor.callLater(1, deferred.callback, None) 
    return deferred 

方法2: 稍微好一點,因爲延遲實際上是發射結果可用

def get_line_count(self): 
    deferred = defer.Deferred() 

    def count_lines(): 
     try: 
      print_file = file(self.print_file_path, "r") 
      self.line_count = sum(1 for line in print_file) 
      print_file.close() 
      deferred.callback(self.line_count) 
     except Exception as inst: 
      deferred.errback(InvalidFile()) 

    reactor.callLater(1, count_lines) 
    return deferred 

注:你也可以指出的是,這兩種都是實際上是同步的,也可能是阻塞方法,(我也許可以使用「MaybeDeferred」?)。 但是,那實際上是我感到困惑的一個方面。

  1. 對於方法2,如果count_lines方法是很慢的(在一些大文件等計數線),將它潛在的「塊」全扭曲應用程序? 我讀了很多關於回調函數和errbacks以及reactor如何一起工作的文檔(回調函數需要快速執行,或者返回延遲本身等等),但是在這種情況下,我只是看不到並且真的很感謝一些指針/例子等

  2. 是否有一些文章/ 明確的解釋,與最好的辦法創建這些「第一」 deferreds應對?我已經閱讀了these excellent articles,他們對一些基本的理解有了很大的幫助,但我仍然覺得我錯過了一件。

  3. 對於阻斷代碼,這會是這樣的情況。典型地爲DeferToThreadreactor.spawnprocess? 我經歷了很多像this onethis article問題閱讀,但我依然沒有就如何處理與文件打交道時可能阻塞的代碼,主要是確保100%的I/O

很抱歉,如果任何這似乎太基本了,但我真的想更徹底地使用Twisted。 (它對於所有更多面向網絡的方面都是一個非常強大的工具)。 謝謝你的時間!

回答

2

是的,你說得對:你需要線程或單獨的進程來避免阻塞Twisted事件循環。使用Deferreds不會奇蹟般地讓你的代碼無阻塞。對於您的問題:

  1. 是的,你會阻止事件循環,如果count_lines是非常緩慢。推遲到一個線程將解決這個問題。

  2. 我用Twisteds documentation來了解Deferreds是如何工作的,但我想你已經經歷過了。關於database support的文章是信息,因爲它清楚地表明這個庫是使用線程構建的。這就是你如何彌合同步與異步的差距。

  3. 如果通話確實阻塞,那麼您需要DeferToThread。 Python本身是單線程的,這意味着一次只有一個線程可以執行Python字節碼。但是,如果您創建的線程無論如何都會阻塞I/O,那麼此模型將正常工作:線程將釋放全局解釋器鎖,並讓其他Python線程運行,包括帶有Twisted事件循環的主線程。

    在代碼中也可以使用非阻塞I/O。例如,這可以使用select模塊完成。在這種情況下,你不需要一個單獨的線程。 Twisted在內部使用這種技術,如果您執行正常的網絡I/O,則不必考慮這一點。但是如果你正在做一些奇特的事情,那麼知道事情是如何構建的,這樣你就可以做同樣的事情。

我希望能讓事情變得更清楚!

+0

非常感謝Martin的快速和徹底的回覆! 1.和2.好的,Thread/Threadpool方法*在這種情況下是有意義的。 – 2012-01-15 12:11:03

+0

3.我傾向於在GIL中謹慎使用Python中的線程,但通常它應該**能夠在大約相同的時間處理運行'count_lines'方法的3-4個線程,而不會搞亂Twisted事件循環(該方法用於小的「任務」,然後通過串行將數據從文件發送到設備) – 2012-01-15 12:12:48

+0

感謝有關選擇模塊的信息,它似乎與Twisted中不同類型的反應器「相關」。我會更詳細地研究它!對於實際應用,不幸的是它只支持Windows平臺上的套接字(因此在Windows上使用扭曲串行支持時存在相當奇怪的限制)。 – 2012-01-15 12:14:30