【问题标题】:Why does Javascript have much fewer blocking functions than Python为什么 Javascript 的阻塞函数比 Python 少得多
【发布时间】:2021-10-11 17:51:28
【问题描述】:

从 Javascript 迁移到 Python,看着 asyncio 让我有点困惑。

作为一个对并发基本概念不熟悉的人,我只是假设对 Javascript 并发的理解很肤浅。

在Javascript中使用async / await的基本理解:

如果我们在 async 函数内运行任何进程,并且 await 是函数的响应,我们实际上是在等待函数在 Promise 上设置值。

完全有意义 - 当Promise 被赋予一个值时,我们还可以使用诸如.then() 之类的回调来处理响应。或者,只需await

无论这里异步的底层实现是什么(例如,所有进程都运行在带有事件循环的单个线程上),我们如何与之交互是否重要?

现在,我转向 Python 并开始使用 asyncio。我们有Futures,就像Promises。一下子就不能使用我的标准库了,比如request.get(...),但是我需要在库中使用非阻塞网络请求比如aiohttp

这里的阻塞/非阻塞是什么意思?我假设这意味着事件循环所在的单个线程被阻塞,所以我们不能并行处理其他函数。

那么我的两个问题是:

  • 单线程阻塞的原因是什么?例如requests.get(...)
  • 为什么大多数函数在 Javascript 中是非阻塞的,而在 Python 中却不是(即我们不需要特定的库,例如 aiohttp)。

那么像Go 这样的语言和它们的goroutines 呢?是否只是一个案例,因为它是一种从一开始就内置并发的新语言,阻塞函数的概念不存在。或者在 Go 中它不是单线程,所以一切都可以本质上并行化?

谢谢:)

【问题讨论】:

  • 据我了解,JavaScript 的阻塞函数可能要少得多,因为它是单线程的,非异步函数中的阻塞函数会冻结整个页面,直到它们完成
  • @VilgotanL 如果他们自己执行的时间过长(例如函数内部的同步大数据处理),他们也可以冻结整个页面
  • 请记住,async / await 是在 2017 年才添加到 Javascript 中的。它们并不是从一开始就被融入到语言中的。
  • @TimRoberts:也就是说,事件循环(这是您实现它们所需要的) 从一开始就被嵌入; Python 没有。

标签: javascript python multithreading async-await python-asyncio


【解决方案1】:

事件循环

Javascript 和 python 的异步 io 使用基于 event loops 的并发模型。

(请注意复数,因为您可能有多个事件循环来处理不同类型的任务,例如磁盘 io、网络 io、ipc、并行计算等)

事件循环的一般概念是,您有很多事情要做,所以您将这些事情放在一个队列中,并且每隔一段时间(比如每纳秒),事件循环会从队列,并运行一小段时间(可能是一毫秒左右),如果尚未完成,则将其推回队列中,或者等待直到将控制权交还给事件循环。


现在回答你的一些问题:

这里的阻塞/非阻塞是什么意思?我认为这意味着 事件循环所在的单线程被阻塞,所以我们无法处理 其他功能并行。

阻塞事件循环

当事件循环正在运行一个任务,并且该任务没有完成或将控制权交还给事件循环时,会发生阻塞事件循环,时间比事件循环安排它运行的时间长。

对于python的requests库,它们使用了一个同步的http库,它不尊重事件循环;因此,在循环中运行这样的任务会使其他耐心等待轮到自己运行的任务饿死,直到请求完成。

为什么大多数函数在 Javascript 中是非阻塞的,而在 Python 中却不是 (即我们不需要特定的库,例如 aiohttp)。

JS

Javascript 中的所有内容都可以阻止事件循环。不阻塞事件循环的唯一方法是通过setTimeout 大量使用回调。但是,如果不小心,即使这些回调运行时间过长,也可能会阻塞事件循环,而不会通过另一个 setTimeout 调用将控制权交还给事件循环。

(如果您从未使用过setTimeout,但在 JS 中使用过 Promise 和异步网络请求,那么您可能正在使用一个库。大多数流行的网络库在浏览器(ajax、axios、fetch 等)基于流行的XMLHttpRequest API,提供异步网络 IO。)

Python

在 python 中,情况略有不同:在 asyncio 之前,没有“事件循环”之类的东西。在 python 解释器继续下一步之前,一切都必须运行完成。这是使 python 非常容易学习的部分原因(我敢说,要创建......)。其原因在于 python GIL 的形式,简单来说,它为任何 python 程序强制执行单一顺序。我鼓励您单击该链接,并阅读 GIL 存在的原因。

那么像Go 这样的语言和它们的goroutines 呢?

注意:我不是围棋程序员,但我看过something

Go 有何不同?

go 处理 goroutine 的方式与 python asyncio/js 如何处理事件循环的唯一区别是 go 更多地使用 os 线程来确保线程被公平调度并充分利用它们运行的​​机器。

虽然 js 回调/异步任务通常与事件循环在同一个线程中运行,但 goroutine 能够在单独的操作系统线程和多个内核上运行,从而为它们提供更高的可用性和更高的并行性。 (在这种情况下,我们几乎可以认为 goroutine 在实际运行时间方面更接近 OS 线程,而绿色线程则受事件循环线程运行时间的限制。 )

【讨论】:

  • 很棒的答案,非常感谢!
猜你喜欢
  • 1970-01-01
  • 2011-11-16
  • 2016-10-08
  • 2020-12-07
  • 2020-03-29
  • 2019-05-22
  • 2017-07-30
  • 2011-10-16
  • 1970-01-01
相关资源
最近更新 更多