Twisted 多线程

Twisted框架管理两种线程:一种是主线程,一种是辅助线程。主线程只有一个,即reactor.run()运行的线程;辅助线程可以有多个,以线程池的方式呈现。

Twisted定义的事件类函数都在主线程中运行。

为了提高运行效率,TWisted框架中大多数内置函数都不是线程安全的(例如:Protocol.transport.write()函数),因此需要将这些内置函数放入到主线程中执行,否则可能导致逻辑错误或者系统崩溃。

使代码在主线程中运行

reactor.callFromThread(func,*args,**kw):可以使代码运行在主线程中;func参数代表要执行的函数

# coding:utf8
# 示例代码(不一定能运行)
from twisted.internet.protocol import Protocol
from twisted.internet import reactor

class MyProtocol(Protocol):
    pass

protocol = MyProtocol()

def must_run_in_main_thread(message):
    protocol.send=True
    protocol.transport.write(message)

def run_in_any_thread():
    reactor.callFromThread(must_run_in_main_thread,'message to...')
    print('the run of must_run_in_main_thread() has been finished')

使代码在辅助线程中运行

在主线程中遇到较耗时的处理时,可以使用reactor.callInThread()函数建立辅助线程

如果辅助线程中处理的数据需要调用主线的函数,可以使用reactor.callFromThread()函数将处理结果传递到主线程

辅助线程执行结果可以通过reactor.callFromThread将数据返回到主线程处理

# coding:utf8
from twisted.internet.protocol import DatagramProtocol
from twisted.internet  import reactor
import time

def log_operation(msg):
    time.sleep(10)
    print('got message before 10 seconds :%s'%(msg,))
    reactor.callFromThread(protocol.transport.write(message.encode('utf8')))

class Echo(DatagramProtocol):
    def datagramReceived(self, datagram: bytes, addr):
        str_msg = atagram.decode('utf8')
        reactor.callInThread(log_operation,str_msg)

protocol = Echo()
port = 8009

reactor.listenUDP(port,protocol)
reactor.run()

配置线程池

可以使用reactor.suggestThreadPoolsize()函数定义线程池中的线程数量

reactor.suggestThreadPoolsize(10) # 辅助线程数量为10

子线程返回数据获取(Defer)

twisted.internet.threads.deferToThread(func,*args,**kw) 创建Defer对象d,开启辅助线程

d.addCallback(func)添加回调函数,用于接收子线程返回的数据

from twisted.internet import reactor, threads

def doLongCalculation(x):
    # .... do long calculation here ...
    return 3*9

def printResult(x):
    print(x)

# run method in thread and get result as defer.Deferred
d = threads.deferToThread(doLongCalculation,9)
d.addCallback(printResult)
reactor.run()

主线程中接收子线程返回的数据

twisted.internet.threads.blockingCallFromThread(reactor,f,*args,**kw)启动新线程,并等待线程返回结果

twisted.web.client.getPage(url:bytes)获取html页面源代码

下例中使用 twisted.web.client.getPage获取网页,并在子线程中获取返回结,reactor.callInThread()在辅助线程中执行(一共开启3个线程,一个主线程,一个辅助线程,一个获取网页的辅助线程)

from twisted.internet import threads, reactor, defer
from twisted.web.client import getPage
from twisted.web.error import Error

def inThread():
    try:
        # 开启线程
        result = threads.blockingCallFromThread(reactor, getPage,
                     "https://www.baidu.com/".encode('utf8'))
    except Error as exc:
        print(exc)
    else:
        print (result.decode('utf8'))
    reactor.callFromThread(reactor.stop)

reactor.callInThread(inThread) # 开启线程
reactor.run()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值