當Deferred遇上Thread Deferred不會自動實現將阻塞過程轉為非阻塞過程,雖然它已經有那樣的機制但還是要你去多走一步。要將阻塞過程轉為真正的非阻塞過程,那 只有借用線程。但至於線程調用你不用太擔心,twisted已為你準備好一個方便的用法。就是將Deferred綁在Thread上,這樣就有了deferToThread,味道不比牛奶加巧克力差。 deferToThread在twisted文檔的說明,洋墨水喝得比較少,就不照字面翻譯了。大概意思是將函數f放在線程裡並作為Deferred返回,args和kwargs是函數f的參數。也就是使用deferToThread返回的是一個帶線程的Deferred,並自動使用callback調用指定的函數f。相當於在線程中運行下面的代碼 d=defer.Deferred().addCallback(f) d.callback(result)

def deferToThread(f, *args, **kwargs): (source) Run a function in a thread and return the result as a Deferred. Parameters f The function to call.

*args positional arguments to pass to f.

**kwargs keyword arguments to pass to f.
Returns A Deferred which fires a callback with the result of f, or an errback with a twisted.python.failure.Failure if f throws an exception.

#!/usr/bin/env python
#coding=utf-8

from twisted.internet import protocol,reactor,defer
from twisted.internet.threads import deferToThread
from twisted.protocols import basic
import time,sys
syscode='big5'

class muProtocol(basic.LineReceiver):

        def connectionMade(self):
                print 'connectionMade'
                self.factory.clients[self]={}
                self.factory.clients[self]['isblankly']=True

def lineReceived(self,data):
        self.factory.clients[self]['isblankly']=False
        self.transport.write(self.factory.getSomething(data))
        if data=='q':
                self.transport.loseConnection()
                self.factory.kungfuTea(data)

class muFactory(protocol.ServerFactory):
        protocol=muProtocol

        def __init__(self):
                reactor.callLater(1,self.timeout)
                self.clients={}

        def timeout(self):
                sys.stdout.write('.')
                sys.stdout.flush()
                reactor.callLater(1,self.timeout)

        def getSomething(self,data):
                return '\n\rServer say: %s\n\r' % data

        def goodTaste(self,data):
                print u'%s:耍下太極,仲加埋嘆下功夫茶,都有排等羅。'.encode(
                syscode,'replace') % data
                time.sleep(10)
                print u'%s,打完收功。'.encode(syscode,'replace') % data
                return data

        def wrongTaste(self,data):
                print u'%s:好味道盡在kung fu tea。'.encode(syscode,'replace') % data

        def kungfuTea(self,data):
                return deferToThread(self.goodTaste,data
                ).addBoth(self.wrongTaste)

reactor.listenTCP(20190,muFactory())
reactor.run()

分析下上面的代碼。 當接收到數據後調用self.factory.kungfuTea(data) def lineReceived(self,data): self.factory.kungfuTea(data) 工廠中的kungfuTea只是使用deferToThread將真正處理數據的過程轉goodTaste為一個線程的Deferred,剩下的東西就和Deferred操作無異。

牛奶加巧克力不錯,老板再來一杯!

原文 http://sites.google.com/site/mypynotes/twisted-1/defertothread