在Tornado中,如何进行非阻塞文件读/写?

时间:2016-08-07 04:27:51

标签: python file-io tornado

我现在已经使用Tornado一段时间了,而且我遇到了时间缓慢的问题(我在this question中询问过这个问题)。同事用户指出的一个可能的问题是我使用常规open("..." , 'w')来编写我的协同例程中的文件,这可能是一段阻塞的代码。

所以我的问题是,有没有办法在Tornado中进行非阻塞文件IO?我在研究中找不到符合我需求的任何东西。

2 个答案:

答案 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>