2

我希望对处理“第一个” deferreds的最佳方法进行一些澄清,即不仅仅是将回调和 errbacks 添加到返回 deferred 的现有 Twisted 方法,而是创建这些原始deferreds 的最佳方法。

作为一个具体的例子,这里有两种相同方法的变体:它只计算一些相当大的文本文件中的行数,并用作延迟链的起点。

方法一: 这个感觉不太好,因为deferred是直接被reactor.callLater方法触发的。

def get_line_count(self):
    deferred = defer.Deferred()

    def count_lines(result):
        try:
            print_file = file(self.print_file_path, "r")
            self.line_count = sum(1 for line in print_file)
            print_file.close()
            return self.line_count
        except Exception as inst:
            raise InvalidFile()

     deferred.addCallback(count_lines)
     reactor.callLater(1, deferred.callback, None)
     return deferred

方法 2:稍微好一点,因为结果可用时, 实际上会触发 deferred

def get_line_count(self):
    deferred = defer.Deferred()

    def count_lines():
        try:
            print_file = file(self.print_file_path, "r")
            self.line_count = sum(1 for line in print_file)
            print_file.close()
            deferred.callback(self.line_count)
        except Exception as inst:
            deferred.errback(InvalidFile())

    reactor.callLater(1, count_lines)
    return deferred

注意:您还可以指出,这两种方法实际上都是同步的,并且可能是阻塞方法,(我也许可以使用“ MaybeDeferred ”?)。但是,这实际上是我感到困惑的方面之一。

  1. 对于方法 2,如果count_lines方法非常慢(计算一些大文件中的行数等),它是否可能会“阻止”整个 Twisted 应用程序?我阅读了很多关于回调和 errbacks 以及反应器如何一起工作的文档(回调需要快速执行,或者自己返回延迟等),但在这种情况下,我只是没有看到并且真的很感激一些指针/例子等

  2. 是否有一些文章/明确的解释来处理创建这些“第一个”延迟的最佳方法?我已经阅读了这些优秀的文章,它们对一些基本的理解有很大帮助,但我仍然觉得我缺少一部分。

  3. 对于阻塞代码,这是DeferToThreadreactor.spawnprocess的典型情况吗?我阅读了很多类似这个这篇文章的问题,但我仍然不能 100% 确定如何处理潜在的阻塞代码,主要是在处理文件 i/o 时

对不起,如果这看起来太基本了,但我真的想更彻底地掌握使用 Twisted 的窍门。(对于所有更多面向网络的方面来说,它都是一个非常强大的工具)。感谢您的时间!

4

1 回答 1

2

是的,你做对了:你需要线程或单独的进程来避免阻塞 Twisted 事件循环。使用 Deferreds 不会神奇地使您的代码非阻塞。对于您的问题:

  1. 是的,如果count_lines非常慢,您会阻止事件循环。将其推迟到线程将解决此问题。

  2. 我使用Twisteds 文档来了解 Deferreds 是如何工作的,但我想你已经经历过。关于数据库支持的文章是信息,因为它清楚地表明该库是使用线程构建的。这就是您弥合同步-异步差距的方式。

  3. 如果呼叫确实阻塞,那么您需要DeferToThread. Python 本身是一种单线程,这意味着一次只有一个线程可以执行 Python 字节码。然而,如果你创建的线程无论如何都会阻塞 I/O,那么这个模型工作正常:线程将释放全局解释器锁,让其他 Python 线程运行,包括带有 Twisted 事件循环的主线程。

    您也可以在代码中使用非阻塞 I/O。例如,这可以通过select模块来完成。在这种情况下,您不需要单独的线程。Twisted 在内部使用这种技术,如果你做普通的网络 I/O,你不必考虑这个。但是,如果您正在做一些异国情调的事情,那么最好知道事物是如何构建的,这样您就可以做同样的事情。

我希望这能让事情更清楚一点!

于 2012-01-15T00:14:38.627 回答