【问题标题】:Non-blocking file access with Twisted使用 Twisted 进行非阻塞文件访问
【发布时间】:2010-12-15 19:16:09
【问题描述】:

我试图弄清楚是否存在使用twisted 进行文件访问的事实上的模式。我看过的很多示例(twisted.python.log、twisted.persisted.dirdbm、twisted.web.static)实际上似乎并不担心文件访问的阻塞。

似乎应该有一些明显的接口,可能继承自 abstract.FileDescriptor,所有文件访问都应该作为生产者/消费者通过它。

我是否遗漏了什么,或者仅仅是在异步编程中,twisted 的主要用途是用于网络,而对于其他文件描述符操作还没有真正解决,不用担心非阻塞 IO 的纯度?

【问题讨论】:

标签: python twisted


【解决方案1】:

fdesc 模块可能对与套接字或管道进行异步通信很有用,但是当给定一个引用普通文件系统文件的 fd 时,它会阻塞 io(并且通过一个相当奇怪的接口)。对于磁盘 io,fdesc 是有效的蛇油;不要使用它。

截至 2017 年 5 月,获得扭曲的异步磁盘 io 的唯一合理方法是将同步 io 调用包装在 deferToThread 中。

【讨论】:

  • 现在是 2020 年。还是这样吗?
  • 是的。 [额外的角色让你很开心。]
【解决方案2】:

经过大量的搜索、试验和错误,我终于想出了如何使用fdesc

from __future__ import print_function

from twisted.internet.task import react
from twisted.internet import stdio, protocol
from twisted.internet.defer import Deferred
from twisted.internet.fdesc import readFromFD, setNonBlocking


class FileReader(protocol.Protocol):
    def __init__(self, filename):
        self.f = open(filename, 'rb')

    def dataReceived(self, data):
        self.transport.write(data)

    def connectionMade(self):
        fd = self.f.fileno()
        setNonBlocking(fd)
        readFromFD(fd, self.dataReceived)

    def connectionLost(self, reason):
        self.f.close()

def main(reactor, filename):
    stdio.StandardIO(FileReader(filename))

[编辑:我也只是想出了一种不需要使用协议的更简单的方法]

def getFile(filename):
    with open(filename) as f:
        d = Deferred()
        fd = f.fileno()
        setNonBlocking(fd)
        readFromFD(fd, d.callback)
        return d


def main(reactor, filename):
    d = getFile(filename)
    return d.addCallback(print)

像这样运行:

react(main, ['/path/to/file'])

【讨论】:

  • 在第二个例子中,如果在 deferred 没有触发的情况下关闭文件是否重要?
  • 好点@Chris。也许最好放弃上下文管理器并在回调中明确关闭文件。
  • 不过,这确实会阻止文件访问。当 fd 指向一个普通的文件系统文件时,Unix 系统会默默地忽略setNonBlocking
  • @NathanielJ.Smith 你有链接到任何说明这一点的文档吗?
【解决方案3】:

我认为您正在寻找fdesc module。有关 Python 中非阻塞 I/O 的更多信息,您还可以观看此video

【讨论】:

    【解决方案4】:

    在 Twisted 有一张公开的票 - #3983

    【讨论】:

      【解决方案5】:

      我不确定你想要实现什么。当您进行日志记录时,Python 将确保(通过全局解释器日志)来自多个线程的日志消息一个接一个地进入文件。

      如果您担心阻塞 IO,那么操作系统会为您的文件添加默认缓冲区(通常为 4KB),您可以在 open() 调用中传递缓冲区大小。

      如果您担心其他问题,请澄清您的问题。

      【讨论】:

      • 什么不清楚?他想知道如何在 Twisted 中不阻塞地读取/写入文件。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多