在 Twisted Web 中调用同步方法

转自 :https://www.soasme.com/2016/08/31/twisted-async-response

发现一个隐藏了很久的BUG,记一笔。

我原来给 Scrapyd 写过一个小插件,希望可以同步等待爬虫的结果,并在接口中返回。

原来的实现是:

class CrawlService(scrapyd.resources.JsonResource):

def render_POST(self, request):
resp = self.DO_SOME_SYNC_OPERATION(request)
return resp

在日志中,发现有大量连续的超时响应,遂发现这个问题。

由于 Twisted 是单线程/事件驱动的,同步调用造成了调度线程被完全堵塞,进而完全无法对外服务。

修复依赖 Twisted 的异步 Response 特性,见Twisted Developer Guide: Asynchronous Response: 我们需要将实现替换为返回 NOT_DONE_YET, 并在返回前触发一个异步操作,在异步操作中调用 request.write, request.finish。 另外,同步调用应当在额外的线程中执行,见Twisted Developer Guide: Using Threads in Twisted: 我们需要将同步操作塞到 callInThread 中执行。

修复如下:

class CrawlService(scrapyd.resources.JsonResource):

def DO_SOME_SYNC_OPERATION(self, request):
pipe = Popen(['scrapy', 'crawl', ...])
out, err = pipe.communicate()
request.write(out)
request.finish()

def render_POST(self, request):
reactor.callInThread(self.DO_SOME_SYNC_OPERATION, request)
return server.NOT_DONE_YET

上段时间写 Tornado 程序,被异步调用蹂躏了一番,这次很容易看出了问题。 修复已经发版到了 pypi 上,最新版本: 0.1.6。 应该不会再出现同步堵塞Event Loop的问题了.

补充:

def render_POST(self, request):

reactor.callInThread(self.DO_SOME_SYNC_OPERATION, request)

  time.sleep(0.1)

return server . NOT_DONE_YET
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值