Неблокируемый доступ к файлам с помощью Twisted - PullRequest
27 голосов
/ 12 ноября 2009

Я пытаюсь выяснить, существует ли шаблон де-факто для доступа к файлу с использованием витой. Множество примеров, на которые я смотрел (twisted.python.log, twisted.persisted.dirdbm, twisted.web.static), похоже, не беспокоятся о блокировке доступа к файлам.

Кажется, что должен быть какой-то очевидный интерфейс, возможно, наследующий от abstract.FileDescriptor, чтобы весь доступ к файлам проходил через него как производитель / потребитель.

Я что-то пропустил или это просто то, что основное применение витой в асинхронном программировании - это работа в сети, и она не была разработана для других операций дескриптора файла, не беспокоясь о чистоте неблокирующего ввода-вывода?

Ответы [ 5 ]

14 голосов
/ 16 марта 2010

Я думаю, вы ищете модуль fdesc . Для получения дополнительной информации о неблокирующем вводе / выводе в Python вы также можете посмотреть это видео .

3 голосов
/ 31 марта 2010

В Twisted есть открытый билет - # 3983 .

2 голосов
/ 04 июня 2017

Модуль fdesc может быть полезен для асинхронного общения с сокетом или каналом, но когда ему предоставляется fd, который ссылается на обычный файл файловой системы, он блокирует io (и при этом через довольно странный интерфейс). Для диска io fdesc - это змеиное масло; не используйте его.

По состоянию на май 2017 года единственный разумный способ получить асинхронный диск io в витой форме - это обернуть синхронные вызовы io в deferToThread.

2 голосов
/ 14 ноября 2015

После долгих поисков, проб и ошибок я наконец понял, как использовать 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'])
0 голосов
/ 12 ноября 2009

Я не уверен, чего ты хочешь достичь. Когда вы ведете запись в журнал, то Python убедится (по протоколу глобального интерпретатора), что сообщения журнала из нескольких потоков поступают в файл один за другим.

Если вас беспокоит блокировка ввода-вывода, тогда ОС добавляет буферы по умолчанию для ваших файлов (обычно 4 КБ), и вы можете передать размер буфера в вызове open().

Если вас беспокоит что-то еще, уточните, пожалуйста, свой вопрос.

...