Twisted 的 Deferred 和 JavaScript 中的 Promise 一样吗?

2024-05-21

我开始在一个需要异步编程的项目中使用 Twisted,并且文档非常好。

所以我的问题是,Twisted 中的 Deferred 与 Javascript 中的 Promise 相同吗?如果不是,有什么区别?


你的问题的答案是Yes and No取决于你为什么问。

Yes:

两者都是扭曲的Deferred和一个 JavaScriptPromise实现一种机制,用于对要按给定顺序运行的同步代码块进行排队,同时与其他同步代码块解耦。

No:

所以Javascript的Promise实际上更类似于Python的Future,解释这一点的空想方式是谈论PromiseResolver被组合成一个Deferred,并声明这会影响您可以使用回调执行的操作。

这一切都非常好,因为它是准确的,但是它并没有真正使任何事情变得更清晰,并且在没有输入数千个几乎肯定会犯错误的单词的情况下,我可能更好地引用一个知道的人关于 Python 的一些东西。

吉多·范·罗森 (Guido van Rossum) 谈延期 https://groups.google.com/forum/#!topic/python-tulip/ut4vTG-08k8/discussion:

这是我尝试解释 Deferred 的伟大想法(并且有很多 )面向以前没有 Twisted 经验的高级 Python 用户。 我还假设您之前考虑过异步调用。只是 为了惹恼 Glyph,我使用 5 星系统来表示重要性 想法,其中 1 星是“好主意,但相当明显”,5 星是 是“辉煌”的。

我展示了很多代码片段,因为有些想法是最好的 那样表达——但我故意省略了很多细节, 有时我会展示有错误的代码,如果修复它们会减少 理解代码背后的想法。 (我会指出这些错误。) 我正在使用Python 3。

特别针对 Glyph 的注释:(a) 将其视为博客草稿 邮政。我非常乐意接受更正和建议 改进。 (b) 这并不意味着我要将 Tulip 更改为 更像 Def​​erred 的模型;但这是针对不同的线程的。

想法 1:返回一个特殊对象而不是接受回调参数

在设计异步生成结果的 API 时,您会发现 你需要一个回调系统。通常是第一个出现的设计 要记住的是传递一个回调函数,当 异步操作完成。我什至见过一些设计,如果你不这样做的话 传入一个回调,操作是同步的——这已经够糟糕的了 我会给它零星。但即使是一星版本也会污染所有 带有额外参数的 API 必须繁琐地传递。 Twisted 的第一个伟大想法是,最好返回一个特殊的 调用者收到后可以添加回调的对象。我 给这个三颗星,因为从中萌芽出许多其他的好东西 想法。这当然类似于期货和期货的基本思想 许多语言和库中都存在 Promise,例如蟒蛇的 并发.futures(PEP 3148,紧随 Java Futures,两者 这适用于线程世界),现在是 Tulip(PEP 3156,使用 类似的设计适用于无线程异步操作)。

想法2:将结果从回调传递到回调

我认为最好先展示一些代码:

class Deferred:
    def __init__(self):
        self.callbacks = []
    def addCallback(self, callback):
        self.callbacks.append(callback)  # Bug here
    def callback(self, result):
        for cb in self.callbacks:
            result = cb(result)

最有趣的部分是最后两行:每行的结果 回调被传递给下一个。这与事情的运作方式不同 在并发.futures 和 Tulip 中,结果(一旦设置)是固定的 作为未来的一个属性。这里的结果可以由每个人修改 打回来。

当一个函数返回 Deferred 时,这将启用一种新模式 调用另一个并转换其结果,这就是收益 这个想法三颗星。例如,假设我们有一个异步函数 读取一组书签,我们想要编写一个异步函数 调用它然后对书签进行排序。而不是发明一个 一个异步函数可以等待另一个异步函数的机制(我们 无论如何稍后会做:-),第二个异步函数可以简单地添加一个 对第一个返回的 Deferred 的新回调:

def read_bookmarks_sorted():
    d = read_bookmarks()
    d.addCallback(sorted)
    return d

该函数返回的 Deferred 表示一个排序列表 书签。如果其调用者想要打印这些书签,则必须添加 另一个回调:

d = read_bookmarks_sorted()
d.addCallback(print)

在异步结果由 Future 表示的世界中,这也是一样的 示例将需要两个单独的 Futures:一个由 read_bookmarks() 表示未排序的列表,以及一个单独的 Future 由 read_bookmarks_sorted() 返回,表示排序列表。

该版本的类中有一个不明显的错误:如果 addCallback() 在 Deferred 已经触发后被调用(即它的 调用了callback()方法)然后通过addCallback()添加了回调 永远不会被调用。解决这个问题很容易,但是很乏味,而且 你可以在 Twisted 源代码中查找它。我会携带这个bug 通过连续的例子——假装你生活在一个世界里 结果永远不会太快。还有其他问题 也采用这种设计,但我宁愿将解决方案称为改进 比错误修复。

旁白:Twisted 的术语选择不佳

我不知道为什么,但是,从项目自己的名称 Twisted 开始 它对事物的名称选择常常让我感到不舒服。为了 例如,我真的很喜欢类名应该是名词的准则。 但“Deferred”是一个形容词,而不仅仅是一个形容词,它是一个 动词的过去分词(而且过长:-)。为什么是 它在一个名为twisted.internet的模块中吗?

然后是“回调”,用于两个相关但不同的 用途:它是用于表示函数的首选术语,该函数将被 当结果准备好时调用,但它也是方法的名称 您调用“触发”延迟,即设置(初始)结果。

别让我开始谈论“errback”这个新词/混成词, 这导致我们...

想法 3:集成错误处理

这个想法只得到两颗星(我相信这会让很多人失望) 扭曲的粉丝)因为这让我很困惑。我还注意到 Twisted 文档在解释它是如何工作时遇到了一些困难——在这种情况下 特别是我发现阅读代码比阅读代码更有帮助 文档。

基本想法很简单:如果解雇的承诺会怎样? 延期结果无法实现?当我们写的时候

d = pod_bay_doors.open()
d.addCallback(lambda _: pod.launch())

HAL 9000 应该如何说“对不起,戴夫。恐怕我不能 去做” ?

即使我们不关心这个答案,如果其中之一我们应该怎么做 回调引发异常?

Twisted 的解决方案是将每个回调分为一个回调和 一个“错误”。但这还不是全部——为了处理异常 由回调引发,它还引入了一个新类“Failure”。 ID 其实喜欢先介绍后者,不介绍 错误返回:

class Failure:
    def __init__(self):
        self.exception = sys.exc_info()[1]

(顺便说一句,很棒的类名。我的意思是,我不是 讽刺。)

现在我们可以重写callback()方法,如下所示:

def callback(self, result):
    for cb in self.callbacks:
        try:
            result = cb(result)
        except:
            result = Failure()

这本身我会给两颗星;回调可以使用 isinstance(result, Failure) 区分常规结果 失败。

顺便说一句,在 Python 3 中,也许可以取消 单独的 Failure 类封装异常,然后使用 内置 BaseException 类。通过阅读代码中的注释, Twisted 的 Failure 类主要存在,以便它可以容纳所有 sys.exc_info()返回的信息,即异常类/类型, 异常实例和回溯,但在 Python 3 中,异常对象 已经保存了对回溯的引用。有一些调试内容 Twisted 的 Failure 类执行标准异常不执行的操作,但是 尽管如此,我认为引入单独的类的大多数原因是 已解决。

但我们不要忘记错误返回。我们更改列表 回调到回调函数对的列表,我们重写 再次callback()方法,如下:

def callback(self, result):
    for (cb, eb) in self.callbacks:
        if isinstance(result, Failure):
            cb = eb  # Use errback
        try:
            result = cb(result)
        except:
            result = Failure()

为了方便起见,我们还添加了一个 errback() 方法:

def errback(self, fail=None):
    if fail is None:
        fail = Failure()
    self.callback(fail)

(真正的errback()函数还有一些特殊情况,可以是 以异常或失败作为参数调用,并且 失败类采用可选的异常参数来防止它 使用 sys.exc_info()。但这些都不是必要的,它使得 代码片段更复杂。)

为了确保 self.callbacks 是一个对的列表,我们还必须 更新 addCallback() (之后调用时仍然无法正常工作 Deferred 已被解雇):

def addCallback(self, callback, errback=None):
    if errback is None:
        errback = lambda r: r
    self.callbacks.append((callback, errback))

如果仅使用回调函数调用此函数,则 errback 将是 传递结果(即失败实例)的虚拟对象 不变。这会保留后续错误的错误条件 处理程序。为了方便添加错误处理程序而无需处理 常规结果,我们添加addErrback(),如下:

def addErrback(self, errback):
    self.addCallback(lambda r: r, errback)

在这里,该对的回调一半将传递(非失败)结果 通过不变到下一个回调。

如果您想获得全部动力,请阅读 Twisted 的简介 延期;最后我会注意到一个错误返回并替换一个 仅通过返回非失败值来获得失败的常规结果 (包括无)。

在我继续讨论下一个想法之前,让我指出有 真正的 Deferred 类中有更多细节。例如,您可以指定 要传递给回调和错误返回的附加参数。但在 紧要关头你可以用 lambda 来做到这一点,所以我把它省略了,因为 用于进行管理的额外代码并未阐明 基本思想。

想法 4:链接延迟

这是一个五星级的想法!有时确实需要一个 回调以等待额外的异步事件,然后才能生成 想要的结果。例如,假设我们有两个基本的异步 操作,read_bookmarks() 和sync_bookmarks(),我们想要一个 联合操作。如果这是同步代码,我们可以编写:

def sync_and_read_bookmarks():
    sync_bookmarks()
    return read_bookmarks()

但是如果所有操作都返回 Deferreds,我们该如何编写呢?随着 链式的想法,我们可以这样做:

def sync_and_read_bookmarks():
    d = sync_bookmarks()
    d.addCallback(lambda unused_result: read_bookmarks())
    return d

之所以需要 lambda,是因为所有回调都是通过结果调用的 值,但 read_bookmarks() 不带参数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Twisted 的 Deferred 和 JavaScript 中的 Promise 一样吗? 的相关文章

  • 在 NumPy 中获取 ndarray 的索引和值

    我有一个 ndarrayA任意维数N 我想创建一个数组B元组 数组或列表 其中第一个N每个元组中的元素是索引 最后一个元素是该索引的值A 例如 A array 1 2 3 4 5 6 Then B 0 0 1 0 1 2 0 2 3 1 0
  • IRichBolt 在storm-1.0.0 和 pyleus-0.3.0 上运行拓扑时出错

    我正在运行风暴拓扑 pyleus verbose local xyz topology jar using storm 1 0 0 pyleus 0 3 0 centos 6 6并得到错误 线程 main java lang NoClass
  • NameError:名称“urllib”未定义”

    CODE import networkx as net from urllib request import urlopen def read lj friends g name fetch the friend list from Liv
  • feedparser 在脚本运行期间失败,但无法在交互式 python 控制台中重现

    当我运行 eclipse 或在 iPython 中运行脚本时 它失败了 ascii codec can t decode byte 0xe2 in position 32 ordinal not in range 128 我不知道为什么 但
  • python pandas 中的双端队列

    我正在使用Python的deque 实现一个简单的循环缓冲区 from collections import deque import numpy as np test sequence np array range 100 2 resha
  • 在pyyaml中表示具有相同基类的不同类的实例

    我有一些单元测试集 希望将每个测试运行的结果存储为 YAML 文件以供进一步分析 YAML 格式的转储数据在几个方面满足我的需求 但测试属于不同的套装 结果有不同的父类 这是我所拥有的示例 gt gt gt rz shorthand for
  • Pandas Dataframe 中 bool 值的条件前向填充

    问题 如何转发 fill boolTruepandas 数据框中的值 如果是当天的第一个条目 True 到一天结束时 请参阅以下示例和所需的输出 Data import pandas as pd import numpy as np df
  • 如何正确取消引用然后删除 JavaScript 对象?

    我想知道从内存中完全取消引用 JavaScript 对象的正确方法 确保删除时不会在内存中悬空 并且垃圾收集器会删除该对象 当我看这个问题时在 JavaScript 中删除对象 https stackoverflow com questio
  • ExpectedFailure 被计为错误而不是通过

    我在用着expectedFailure因为有一个我想记录的错误 我现在无法修复 但想将来再回来解决 我的理解expectedFailure是它会将测试计为通过 但在摘要中表示预期失败的数量为 x 类似于它如何处理跳过的 tets 但是 当我
  • 循环中断打破tqdm

    下面的简单代码使用tqdm https github com tqdm tqdm在循环迭代时显示进度条 import tqdm for f in tqdm tqdm range 100000000 if f gt 100000000 4 b
  • 使用 Javascript 设置 cookie [重复]

    这个问题在这里已经有答案了 我正在尝试构建我的第一个移动应用程序 它需要连接到我的 mysql 数据库并使用 json 返回数据 这很好 目前我有一个登录系统 一旦确定用户名和密码存在 它就会返回一条成功消息 对于下一步 我想在我的页面上使
  • 从 pygame 获取 numpy 数组

    我想通过 python 访问我的网络摄像头 不幸的是 由于网络摄像头的原因 openCV 无法工作 Pygame camera 使用以下代码就像魅力一样 from pygame import camera display camera in
  • 如何在 Django 中使用并发进程记录到单个文件而不使用独占锁

    给定一个在多个服务器上同时执行的 Django 应用程序 该应用程序如何记录到单个共享日志文件 在网络共享中 而不保持该文件以独占模式永久打开 当您想要利用日志流时 这种情况适用于 Windows Azure 网站上托管的 Django 应
  • Python:计算字典的重复值

    我有一本字典如下 dictA unit1 test1 alpha unit1 test2 beta unit2 test1 alpha unit2 test2 gamma unit3 test1 delta unit3 test2 gamm
  • 用于运行可执行文件的python多线程进程

    我正在尝试将一个在 Windows 上运行可执行文件并管理文本输出文件的 python 脚本升级到使用多线程进程的版本 以便我可以利用多个核心 我有四个独立版本的可执行文件 每个线程都知道要访问它们 这部分工作正常 我遇到问题的地方是当它们
  • 什么是 WKWebView 中的 WKErrorDomain 错误 4

    fatal error LPWebView encounters an error Error Domain WKErrorDomain Code 4 A JavaScript exception occurred UserInfo 0x7
  • Python:元类属性有时会覆盖类属性?

    下面代码的结果让我感到困惑 class MyClass type property def a self return 1 class MyObject object metaclass MyClass a 2 print MyObject
  • 如何通过索引访问 JSON 对象中的字段

    我知道这不是最好的方法 但我别无选择 我必须通过索引访问 JSONObject 中的项目 访问对象的标准方法是只写this objectName or this objectName 我还找到了一种获取 json 对象内所有字段的方法 fo
  • 使用velocity.js制作可拖动元素的动画

    我正在使用velocity js 为用户拖动的可拖动 SVG 元素设置动画 然而 velocity js 将先前的 mousemove 坐标排队并通过所有后续的 mousemove 坐标进行动画处理 我想要的是velocity js 不要对
  • PyAudio ErrNo 输入溢出 -9981

    我遇到了与用户相同的错误 Python 使用 Pyaudio 以 16000Hz 录制音频时出错 https stackoverflow com questions 12994981 python error audio recording

随机推荐

  • 有没有办法让 React 为孩子自动定义“键”?

    我正在学习 React 我偶然发现了 动态儿童 的这个怪癖 带有代码示例的序言 Render Pass 1
  • 使用中断选项顺序执行函数

    我的操作系统中有一个线程 它以固定的时间间隔被调用 然后顺序执行 10 15 个不同函数的列表 每个函数都有一个返回参数 该参数要么为 0 正常 要么为非 0 错误 看起来像这样 while 1 error function 1 error
  • 使用 matplotlib 从“列表列表”绘制 3D 曲面

    我已经搜索了一些 虽然我可以找到许多有用的网格网格示例 但没有一个清楚地表明我如何将列表列表中的数据转换为可接受的形式 以适应我所讨论的各种方式 当谈到 numpy matplotlib 以及我所看到的建议的术语和步骤顺序时 我有点迷失 我
  • 按位运算符简单地翻转整数中的所有位?

    我必须翻转整数的二进制表示形式中的所有位 鉴于 10101 输出应该是 01010 当与整数一起使用时 完成此操作的按位运算符是什么 例如 如果我正在编写类似的方法int flipBits int n 什么会进入身体 我只需要翻转数字中已经
  • C# using 语句是否执行 try/finally ?

    假设我有以下代码 private void UpdateDB QuoteDataSet dataSet Strint tableName using SQLiteConnection conn new SQLiteConnection co
  • 参考新 CSPROJ 格式的 GAC 程序集?

    我使用的是 Visual Studio 2019 预览版 2 1 我有一个 NET Framework 4 6 1 类库 C 项目 其中有一些采用旧 csproj 项目格式 ToolsVersion 15 0 的 Azure 引用 这个旧的
  • Twitter Bootstrap 中的五个相等的列

    我想在我正在构建的页面上有 5 个相等的列 但我似乎无法理解这里如何使用 5 列网格 http web archive org web 20120416024539 http domain7 com mobile tools bootstr
  • 如何淡化循环背景图像?

    这里的菜鸟 我试图让我的静态背景变成一个轮播 我当前的html看起来像这样 div class pageContent div 和我的CSS body background url http placehold it 1600x1200 n
  • 如何在 Python 中将 pdf 文件附加到 MIME 电子邮件?

    我正在制作一个自动邮件发送程序 Python 3 6 1 用于电子邮件营销 我在附加 PDF 文件时遇到问题 邮件中的 PDF 文件的文件名和页数是正确的 但 PDF 文件始终为空白 并且其大小增加 我尝试了三种不同的方法 其他两种方法不起
  • 通过 sed 使用 unix 变量将数据附加到每行末尾[重复]

    这个问题在这里已经有答案了 我有一个文件 我想使用 SED 将值附加到每行末尾的 unix 变量中 我已经通过 AWK 实现了这一点 但我想在 SED 中实现 像这样的东西 我已经尝试过以下命令 但它不起作用 sed i s BATCH R
  • SASS如何在旋转body时使页面完整的高度和宽度?

    我必须旋转我的身体并做到这一点全高 and 全屏宽度 嗯 我用的是vh公制并且非常适合width但身高还是不太合适 我不得不旋转 90 度但是height and width仍然指相同的方向not rotate PS 我添加了 red以便更
  • 如何动态添加和删除jquery选项卡?

    我有一个 aspx 页面 上面有 2 个静态 jquery 选项卡 单击其中一个选项卡上的按钮后 我想动态添加一个新选项卡 该选项卡从另一个 aspx 页面加载其内容 我也尝试使用以下示例 http jquery ui googlecode
  • 在浏览器中打开 URL,即使我的应用程序为其注册了意图过滤器

    我的应用程序为某些 URL 注册了一个意图过滤器 因为它可以处理来自这些 URL 的数据 但是 在应用程序内部 我想提供一个按钮来在浏览器中打开这样的 URL 也就是说 如果设置了默认浏览器 则在默认浏览器中打开它 否则提供一个选择器 就像
  • 别名模板的包扩展

    似乎可以扩展 pack 参数only代替别名模板的 pack 参数 对于类或函数模板来说 情况并非如此 template
  • 编译成 C/C++ 源代码的编程语言? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Python 3 os.urandom

    在哪里可以找到完整的教程或文档os urandom 我需要获得一个随机 int 来从 80 个字符的字符串中选择一个字符 如果你只需要一个随机整数 你可以使用random randint a b 来自随机模块 http docs pytho
  • iOS 11 浏览器图像错误

    在 iOS 11 中滚动页面时出现以下错误 在 Firefox Safari 和 Chrome 中 在 Android 设备中 不会发生该错误 这些是背景图像 我不知道这是否是导致错误的原因 图 2 显示了图像在 Android 中的用途和
  • 使用 IntlDateFormatter 转换非公历日期

    我应该如何使用将非公历日期转换为其他日历类型IntlDateFormatter 我要转换 1392 01 02 from persian to islamic日历 我尝试了以下代码 但它没有转换日历 formatter IntlDateFo
  • 我的 Android 设备需要安装哪个驱动程序才能运行我的应用程序?

    我购买了 intex mobile 来在真实设备中测试我的 Android 应用程序 然而 该设备不存在于 OEM USB 驱动程序列表中 android 提供的设备列表中 我检查了 intex 官方网站 但不确定到底需要安装哪个驱动程序
  • Twisted 的 Deferred 和 JavaScript 中的 Promise 一样吗?

    我开始在一个需要异步编程的项目中使用 Twisted 并且文档非常好 所以我的问题是 Twisted 中的 Deferred 与 Javascript 中的 Promise 相同吗 如果不是 有什么区别 你的问题的答案是Yes and No