了解异步·事件驱动的编程 预测未来的最好方法就是发明它外文翻译资料

 2022-03-25 08:03

Understanding Asynchronous

Event-Driven Programming

The best way to predict the future is to invent it.

— Alan Kay

Eliminating blocking processes through the use of event-driven, asynchronous I/O is Node#39;s primary organizational principle. We#39;ve learned how this design helps developers in shaping information and adding capacity: lightweight, independent, and share-nothing processes communicating through callbacks synchronized within a predictable event loop.

Accompanying the growth in the popularity of Node is a growth in the number of well-designed evented systems and applications. For a new technology to be successful, it must eliminate existing problems and/or offer to consumers a better solution at a lower cost in terms of time or effort or price. In its short and fertile lifespan, the Node community has collaboratively proven that this new development model is a viable alternative to existing technologies. The number and quality of Node-based solutions powering enterprise-level applications provide further proof that these new ideas are not only novel, but preferred.

In this chapter we will delve deeper into how Node implements event-driven programming. We will begin by unpacking the ideas and theories that event-driven languages and environments derive from and grapple with, in an effort to clear away misconceptions and encourage mastery. Following this introduction, more detail on how timers, callbacks, I/O events, flow control, and the event loop are implemented and used will be laid out. Theory will be practiced as we build up a simple but exemplary file and data-driven applications, highlighting Node#39;s strengths, and how it is succeeding in its ambition to simplify network application designs.

Broadcasting events

It is always good to have an accurate understanding of the total eventual cost of asking for a service to be performed.

I/O is expensive. In the following chart (taken from Ryan Dahl#39;s original presentation on Node) we can see how many clock cycles typical system tasks consume. The relative cost of I/O operations is striking.

L1 cache

3 cycles

L2 cache

14 cycles

RAM

250 cycles

Disk

41,000,000 cycles

Network

240,000,000 cycles

The reasons are clear enough: a disk is a physical device, a spinning metal platter that buses data at a speed that cannot possibly match the speed of an on-chip or near-chip cache moving data between the CPU and RAM (Random Access Memory). Similarly, a network is bound by the speed in which data can travel through its connecting 'wires', modulated by its controllers. Even through fiber optic cables, light itself needs 0.1344 seconds to travel around the world. In a network used by billions of people regularly interacting across great distances, this sort of latency builds up.

In the traditional marketplace described by an application running on a blocking system the purchase of a file operation requires a significant expenditure of resources, as we can see in the preceding table. Primarily this is due to scarcity: a fixed number of processes, or 'units of labor' are available, each able to handle only a single task, and as the availability of labor decreases, its cost (to the client) increases.

The breakthrough in thinking reflected by Node#39;s design is simple to understand once one recognizes that most worker threads spend their time waiting—for more instructions, a sub-task to complete, and so on. For example, a process assigned to service the command format my hard drive will dedicate all of its allotted resources to managing a workflow something like the following:

  • Communicate to a device driver that a format request has been made
  • Idle, waiting for an 'unknowable' length of time
  • Receive the signal format is complete
  • Notify the client
  • Clean up; shut down

In the preceding figure we see that an expensive worker is charging the client a fixed fee per unit of time regardless of whether any useful work is being done (the client is paying equally for activity and idleness). Or to put it another way, it is not necessarily true, and most often simply not true, that the sub-tasks comprising a total task each require identical effort or expertise, and therefore it is wasteful to pay a premium price for such cheap labor.

Sympathetically, we must also recognize that this worker can do no better even if ready and able to handle more work—even the best intentioned worker cannot do anything about I/O bottlenecks. The worker here is I/O bound.

A blocking process is therefore better understood as an idle process, and idle processes are bottlenecks within the particular task and for the overall application flow. What if multiple clients could share the same worker, such that the moment a worker announces availability due to an I/O bottleneck, another job from another client could be started?

Node has commoditized I/O through the introduction of an environment where system resources are (ideally) never idle. Event-driven programming as implemented by Node reflects the simple goal of lowering overall system costs by encouraging the sharing of expensive labor, mainly by reducing the number of I/O bottlenecks to zero. We no longer have a powerless chunk of rigidly-priced unsophisticated labor; we can reduce all effort into discrete units with precisely delineated shapes and therefore admit much more accurate pricing. Identical outlays of capital can fund a much larger number of completed transactions, increasing the efficiency of the market and the potential of the m

全文共108093字,剩余内容已隐藏,支付完成后下载完整资料


2.了解异步·事件驱动的编程

预测未来的最好方法就是发明它。

-艾伦凯

通过使用事件驱动的方法消除阻塞进程, 异步 i/o 是节点的主要组织原则。我们已经了解到, 此设计如何帮助开发人员塑造信息和添加容量: 轻量级、独立和共享-任何进程通过回调在可预知的事件循环中同步进行通信。

伴随着节点受欢迎程度的增长, 设计良好的 evented 系统和应用的数量也在增长。为了获得成功, 它必须消除现有的问题和/或提供给消费者一个更好的解决方案, 以较低的成本, 在时间或努力或价格方面。在其短暂和肥沃的生命周期中, 节点社区协同证明, 这种新的开发模式是现有技术的可行替代方案。基于节点的解决方案的数量和质量为企业级应用程序供电提供了进一步的证据, 证明这些新思想不仅新颖, 而且更可取。

在本章中, 我们将深入探讨节点如何实现事件驱动编程。我们将首先解开事件驱动的语言和环境衍生出来的思想和理论, 努力消除误解, 鼓励掌握。在本介绍之后, 将详细介绍如何实现计时器、回调、i/o 事件、流控制以及事件循环。当我们建立一个简单但堪称典范的文件和数据驱动应用程序, 强调节点的优势, 以及它如何成功地实现简化网络应用程序设计的雄心时, 理论将被实践。

广播活动

准确了解要求执行服务的总最终成本总是好的。

i/o 很贵。在下面的图表中 (取自Ryan在节点上的原始演示文稿), 我们可以看到典型系统任务消耗的时钟周期数。i/o 操作的相对成本是惊人的。

L1 缓存

3个周期

L2 缓存

14个周期

ram

250个周期

磁盘

4100万个周期

网络

2.4亿个周期

原因很清楚: 磁盘是一个物理设备, 一个旋转的金属盘片, 它的速度不可能与芯片上或近芯片缓存在 CPU 和 RAM (随机存取内存) 之间移动数据的速度相匹配。同样, 网络也受其控制器调制的数据传输速度的限制。即使通过光纤光缆, 光本身也需要0.1344 秒的时间环游世界。在一个网络中, 成千上万的人经常在很远的距离内进行交互, 这种延迟会建立起来。

在一个在阻塞系统上运行的应用程序所描述的传统市场中, 文件操作的购买需要大量的资源开销, 正如我们在上表中看到的那样。这主要是由于稀缺性: 有固定数量的工序, 或 '劳动力单位' 可用, 每个只能处理一个单一的任务, 随着劳动力的可用性降低, 其成本 (对客户) 增加。

节点设计所反映的思维突破很容易理解, 一旦认识到大多数工作线程都花时间等待--更多的指令, 一个子任务完成, 等等。例如, 分配给服务命令格式化我的硬盘的进程将将其所有分配的资源都用于管理工作流, 如下所示:

· 与已发出格式请求的设备驱动程序通信

· 空闲, 等待 '不可知的' 时间长度

· 接收信号格式已完成

· 通知客户端

· 清理; 关闭

在前面的图中, 我们看到一个昂贵的工人向客户收取固定的费用, 每单位的时间, 无论是否有任何有用的工作正在进行 (客户是平等支付的活动和闲置)。或者以另一种方式, 它不一定是真实的, 而且通常是不真实的, 包括总任务的子任务每个需要相同的努力或专门知识, 因此, 为这种廉价劳动力支付溢价价格是浪费的。

同情地说, 我们还必须认识到, 即使准备好并能够处理更多的工作, 这个工人也不会做得更好--即使是最好心的工人也不能对 i/o 瓶颈做任何事情。此处的工作人员是 i/o绑定.

因此,阻塞进程被更好地理解为空闲进程,空闲进程是特定任务和整个应用程序流中的瓶颈。如果多个客户端可以共享同一工作人员, 这样当工作人员由于 i/o 瓶颈而宣布可用性时, 另一个客户端的另一个作业就可以启动了吗?

节点通过引入一个系统资源 (理想地) 从不空闲的环境来商品化 i/o。由节点实现的事件驱动编程反映了通过鼓励共享昂贵的人工来降低总体系统成本的简单目标, 主要是将 i/o 瓶颈的数量减少到零。我们不再有一个无力的一大块刚性价格的简单劳动;我们可以把所有的努力都用精确划定的形状减少到离散单元中, 从而更准确地承认价格。相同的资本支出可以为大量完成的交易提供资金, 提高市场的效率和市场在新产品和新产品类别方面的潜力。在相同的基础结构上, 可以以相同的成本处理更多的并发事务。

如果进程的开始、停止和空闲状态被理解为可以订阅和操作的事件, 我们就可以开始讨论如何在这个新的内部构造极其复杂的系统, 并且在心里很容易掌握模型。

在哪些环境中, 许多客户端工作的协作计划看起来像?以及如何在处理事件之间传递消息?

合作

上一节中描述的工作流是阻塞服务器的一个示例。每个工作分配一个任务或进程, 每个进程只能接受一个工作请求。他们将阻止其他请求, 即使空转:

更可取的是一个协作的工作环境, 在那里工作人员可以被分配新的任务来做, 而不是空转。为了实现这样一个目标, 需要的是一个虚拟切换面板, 可以将服务请求分派给可用的工作人员, 并在那里工作人员可以通知交换机其可用性。

实现这一目标的一个方法是保持有一个可用的劳动力池的想法, 但通过将任务委派给不同的工人来提高效率:

此方法的一个缺点是需要完成的调度和工作人员监视的数量。调度程序必须在连续的请求流中进行操作, 同时还要管理来自工作人员的有关其可用性的消息, 并将请求巧妙地分解为可管理的任务, 并有效地对其进行排序, 以使最少的工作人员空闲。

也许最重要的是, 当所有的工人都被订满的时候会发生什么?调度程序是否开始删除客户端的请求?调度也是资源密集型的, 甚至对调度员的资源也有限制。如果请求继续到达, 并且没有工作人员可以为他们提供服务, 那么调度器是做什么工作的?管理队列?我们现在的情况下, 调度员不再做正确的工作 (调度), 并已成为负责簿记和保管清单, 进一步降低运营效率。

排队

为了避免压倒任何人, 我们可以在客户端和调度器之间添加一个缓冲区。

这个新员工负责管理客户关系。客户端不直接与调度员交谈, 而是向服务管理器发出通知, 传递经理请求, 并在将来的某个时候接到调用, 表示任务已完成。工作请求被添加到一个优先级的工作队列 (一堆订单中最重要的一叠), 而这个经理等待另一个客户端走进门。下图描述了以下情况:

当工作人员空闲时, 调度员可以获取堆栈上的第一个项目, 传递所有包工作人员已经完成的任务, 并且通常保持一个正常的工作环境, 没有任何东西被丢弃或丢失。如果在所有工作人员都空闲且任务队列为空的情况下, office 可以休眠一段时间, 直到下一个客户端到达为止。

最后一个模型激发节点的设计。主要修改是仅使用 i/o 任务占用工作人员池, 并将剩余工时委派给 V8 的单线程。如果 JavaScript 程序被理解为客户端, 则节点是通过所提供的指令运行的服务管理器并对它们进行排序。当遇到潜在的阻塞任务 (i/o、计时器和流) 时, 会将其移交给调度程序 (libuv 线程池)。否则, 指令将排队等待事件循环弹出并执行。

侦听事件

在上一章中, 我们被引入到 EventEmitter 接口。这是我们在将章节移动到章节时遇到的主要事件接口, 因为它为公开 evented 接口 (如文件和网络流) 的许多节点对象提供了原型类。各种 关闭, 退出, 数据, 以及由不同模块 api 公开的其他事件, 信号显示 EventEmitter 的存在接口, 并且我们将在我们的进度中学习这些模块和用例.

相反, 本节的主要目的是讨论一些鲜为人知的事件源-信号、子进程通信、文件系统更改事件和延迟执行。

信号

在许多方面, evented 编程就像硬件中断编程一样。中断按照他们的名字来说明。他们使用他们的能力来中断任何控制器或 CPU 或任何其他设备正在做的事情, 要求他们的特殊需要立即得到服务。

实际上, 节点进程object 公开标准可移植操作系统接口(POSIX) 信号名称, 这样节点进程就可以订阅这些系统事件.

信号是在 unix、类似于 unix 和其他符合 POSIX 标准的操作系统中使用的一种有限的进程间通信形式。它是发送到进程或同一进程中的特定线程的异步通知, 以便通知发生的事件。

-http://en.wikipedia.org/wiki/POSIX_signal

这是向操作系统 (OS) 信号事件公开节点进程的一种非常优雅和自然的方式。人们可能会配置侦听器来捕获指示节点进程重新启动或更新某些配置文件的信号, 或者干脆清理和关闭。

例如, SIGINT信号在其控制终端检测到Ctrl C (或等效) 击键时发送到进程。此信号指示已请求中断的进程。如果节点进程已将回调绑定到此事件, 则该函数可能在终止前记录请求, 执行其他清理工作, 甚至忽略请求:

setInterval(function() {}, 1e6); process.on(#39;SIGINT#39;, function() { console.log(#39;SIGINT signal received#39;); process.exit(1); })

在这里, 我们设置了一个很远的时间间隔, 这样进程就不会立即终止, 并且 SIGINT 侦听器。当用户向控制此进程的终端发送Ctrl C中断时, 将在终端上写入消息SIGINT 信号, 进程将终止。

现在考虑一个节点进程正在进行一些正在进行的工作 (如分析日志) 的情况。能够向该进程发送信号 (如更新配置文件重新启动扫描) 可能很有用。您可能希望从命令行发送此类信号。您可能更愿意使用另一个进程-称为进程间通信(IPC).

创建名为的文件 ipc 包含以下代码:

setInterval(function() {}, 1e6); process.on(#39;SIGUSR1#39;, function() { console.log(#39;Got a signal!#39;); });

SIGUSR1 (和 SIGUSR2) 是用户定义的信号 (它们由没有特定的操作触发)。这使它们成为自定义功能的理想信号.

若要向进程发送命令, 必须确定其进程 ID (PID)。随着 PID 在手, 过程可以解决, 因此沟通。如果在通过节点运行 ipc. js 之后分配给的 PID 是 123, 那么我们可以使用下面的命令行发送该进程 SIGUSR1 信号:

kill –s SIGUSR1 123

在UNIX 中查找给定节点进程的 PID 的一种简单方法是在系统进程列表中搜索表示进程正在运行的程序的名称。如果 ipc 当前正在执行, 则通过在控制台/终端中输入以下命令行来找到其 PID:

节点设计的一个基本部分是在并行执行或缩放系统时创建或分叉进程, 例如, 与创建线程池相反。在本书中, 我们将以各种方式使用子进程, 并学习如何创建和使用它们。这里的重点将是了解如何处理子进程之间的通信事件。

创建子进程一个人只需调用分的方法 child_process 模块, 向其传递要在新进程中执行的程序文件的名称:

var cp = require(#39;child_process#39;); var child = cp.fork(__dirname #39;/lovechild.js#39;);

这样, 任何数量的子流程都可以继续运行。此外, 在多核机器上, 分叉过程将 (由 OS) 分配给不同的核心。跨核心 (甚至是其他机器) 传播节点进程和管理 IPC 是 (一种) 方法, 以稳定、可理解和可以预测的方式来扩展节点应用程序。

扩展前面的, 我们现在可以有分叉进程 (父)

全文共46843字,剩余内容已隐藏,支付完成后下载完整资料


资料编号:[15307],资料为PDF文档或Word文档,PDF文档可免费转换为Word

原文和译文剩余内容已隐藏,您需要先支付 30元 才能查看原文和译文全部内容!立即支付

以上是毕业论文外文翻译,课题毕业论文、任务书、文献综述、开题报告、程序设计、图纸设计等资料可联系客服协助查找。