我现在已经使用Tornado一段时间了,而且我遇到了时间缓慢的问题(我在this question中询问过这个问题)。同事用户指出的一个可能的问题是我使用常规open("..." , 'w')
来编写我的协同例程中的文件,这可能是一段阻塞的代码。
所以我的问题是,有没有办法在Tornado中进行非阻塞文件IO?我在研究中找不到符合我需求的任何东西。
答案 0 :(得分:1)
将与文件IO关联的所有代码移动到用run_on_executor装饰的单独函数。
import os
import io
from concurrent.futures import ThreadPoolExecutor
from PIL import Image
class UploadHandler(web.RequestHandler):
executor = ThreadPoolExecutor(max_workers=os.cpu_count())
@gen.coroutine
def post(self):
file = self.request.files['file'][0]
try:
thumbnail = yield self.make_thumbnail(file.body)
except OSError:
raise web.HTTPError(400, 'Cannot identify image file')
orig_id, thumb_id = yield [
gridfs.put(file.body, content_type=file.content_type),
gridfs.put(thumbnail, content_type='image/png')]
yield db.imgs.save({'orig': orig_id, 'thumb': thumb_id})
self.redirect('')
@run_on_executor
def make_thumbnail(self, content):
im = Image.open(io.BytesIO(content))
im.convert('RGB')
im.thumbnail((128, 128), Image.ANTIALIAS)
with io.BytesIO() as output:
im.save(output, 'PNG')
return output.getvalue()
答案 1 :(得分:0)
我提供了另一个答案,因为事实证明,在单独的线程中读取/写入整个文件对大文件不起作用。您无法在一个块中接收或发送大文件的全部内容,因为您可能没有足够的内存。
对我来说,当ioloop的主线程中的块处理器无法跟上速度时,找出如何阻止读写器线程并非易事。当文件读取操作比块处理器快得多时,以及当文件读取操作较慢时,下面的实现有效。通过异步队列和锁的组合实现同步,并且它不会以任何方式阻止ioloop的线程。
锁只在循环的线程中释放,它永远不会被获取,那里没有竞争条件。
我不认为这会被接受作为答案,但由于我需要一段时间来弄明白,我想这可能会对他们的实施有所帮助。
这不仅适用于文件读/写操作,而且适用于任何消费者/生产者对,它们在一个单独的线程中有一面,另一面在ioloop中。
<inputTextBox (inputClick) = this[ie.onClick]()></inputTextBox>