既然 JavaScript 是单线程的,那么 HTML5 中的 web worker 是如何做多线程的呢?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9708113/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 07:32:44  来源:igfitidea点击:

Since JavaScript is single-threaded, how are web workers in HTML5 doing multi-threading?

javascripthtmlweb-worker

提问by James Drinkard

I've been reading about web workers in HTML5, but I know JavaScript is single-threaded.

我一直在阅读有关 HTML5 网络工作者的文章,但我知道 JavaScript 是单线程的。

My question is:

我的问题是:

How are web workers doing multi-threaded work then? or how are they simulating it if it's not truely multi-threaded? Doesn't seem clear to me here.

那么网络工作者如何进行多线程工作呢?或者如果它不是真正的多线程,他们如何模拟它?我在这里似乎不清楚。

回答by robertc

As several comments have already pointed out, Workers really are multi-threaded.

正如一些评论已经指出的那样,Worker 确实是多线程的。

Some points which may help clarify your thinking:

一些可能有助于澄清您的想法的要点:

  • JavaScript is a language, it doesn't define a threading model, it's not necessarily single threaded
  • Most browsers have historically been single threaded (though that is changing rapidly: IE, Chrome, Firefox), and most JavaScript implementations occur in browsers
  • Web Workers are not part of JavaScript, they are a browser feature which can be accessed through JavaScript
  • JavaScript 是一种语言,它没有定义线程模型,也不一定是单线程的
  • 大多数浏览器历来都是单线程的(尽管这种情况正在迅速变化:IEChromeFirefox),并且大多数 JavaScript 实现发生在浏览器中
  • Web Workers 不是 JavaScript 的一部分,它们是可以通过 JavaScript 访问的浏览器功能

回答by Antonio

A bit late, but I just asked myself the same question and I came up with the following answer:
Javascript in browsers is always single-threaded, and a fundamental consequence is that "concurrent" access to variables (the principal headache of multithreaded programming) is actually not concurrent; this is true with the exception of webworkers, which are actually run in separate threads and concurrent access to variables must be dealt with in a somewhat explicit way.

有点晚了,但我只是问自己同样的问题,我想出了以下答案:
浏览器中的 Javascript 总是单线程的,一个基本的后果是“并发”访问变量(多线程编程的主要问题)实际上不是并发的;这是真的,除了 webworkers,它们实际上运行在单独的线程中,并且必须以某种明确的方式处理对变量的并发访问

I am not a JavaScript ninja, but I too was convinced that JavaScript in browser is provided as a single threaded process, without paying much attention to whether it was true or to the rationale behind this belief.
A simple fact that supports this assumption is that when programming in JavaScript you don't have to care about concurrent access to shared variables. Every developer, without even thinking of the problem, writes code as if every access to a variable is consistent.
In other words, you don't need to worry about the so called Memory model.

我不是 JavaScript 忍者,但我也确信浏览器中的 JavaScript 是作为单线程进程提供的,没有过多关注它是否真实或这种信念背后的基本原理。
支持这一假设的一个简单事实是,在用 JavaScript 编程时,您不必关心对共享变量的并发访问。每个开发人员甚至没有考虑问题,编写代码就好像对变量的每次访问都是一致的。
换句话说,您无需担心所谓的Memory 模型

Actually there is no need of looking at WebWorkers to involve parallel processing in JavaScript. Think of an (asynchronous) AJAX request. And think how carelessly you would handle concurrent access to variables:

实际上没有必要看 WebWorkers 来涉及 JavaScript 中的并行处理。考虑一个(异步)AJAX 请求。想想你会多么粗心地处理对变量的并发访问:

var counter = 0;

function asyncAddCounter() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4) {
      counter++;
    }
  };
  xhttp.open("GET", "/a/remote/resource", true);
  xhttp.send();
}

asyncAddCounter();
counter++;

What is the value of counterat the end of the process? It is 2. It doesn't matter that it is read and written "concurrently", it will never result in a 1. This means that access to counteris always consistent. If two threads where really accessing the value concurrently, they both could start off by reading 0and both write 1in the end.

counter过程结束时的价值是什么?它是2。“并发”读取和写入无关紧要,它永远不会导致1. 这意味着访问counter始终是一致的。如果两个线程真正同时访问该值,则它们都可以从读取开始,最后0都写入1

In browsers, the actual data-fetching of a remote resource is hidden to the developer, and its inner workings are outside the scope of the JavaScript API (what the browser let's you control in terms of JavaScript instructions). As far as the developer is concerned, the resultof the network request is processed by the main thread.
In short, the actual carrying out of the requestis not visible, but the invocation of the callback(handling the result by custom JavaScript code) is executed by the main thread.
Possibly, if it wasn't for the webworkers, the term "multithreading" wouldn't ever enter the Javascript world.

在浏览器中,远程资源的实际数据获取对开发人员是隐藏的,其内部工作超出了 JavaScript API 的范围(浏览器让您根据 JavaScript 指令控制什么)。对开发者而言,网络请求的结果由主线程处理。
简而言之,请求的实际执行是不可见的,但回调的调用(通过自定义 JavaScript 代码处理结果)由主线程执行。
可能,如果不是网络工作者,术语“多线程”永远不会进入 Javascript 世界。

The execution of the request and the asynchronousinvocation of the callback is actually achieved by using event loops, not multithreading. This is true for several browsers and obviously for Node.js. The following are some references, in some cases a bit obsolete, but I guess that the main idea is still retained nowadays.

请求的执行和回调的异步调用实际上是使用事件循环来实现的,而不是多线程。这适用于多种浏览器,显然适用于 Node.js。以下是一些参考资料,在某些情况下有点过时,但我想现在仍然保留主要思想。

This fact is the reason why JavaScript is said to be Event-drivenbut not multithreaded.
Notice that JavaScript thus allows for asynchronousidioms, but not parallelexecution of JavaScript code (outside webworkers). The term asynchronousjust denotes the fact that the result of two instructions might be processed in scrambled order.

这个事实就是 JavaScript 被称为事件驱动而不是多线程的原因。
请注意,JavaScript 因此允许异步习惯用法,但不允许并行执行 JavaScript 代码(在 webworkers 之外)。术语异步只是表示两个指令的结果可能以加扰顺序处理的事实。

As for WebWorkers, they areJavaScript APIs that give a developer control over a multithreaded process.
As such, they provide explicit ways to handle concurrent access to shared memory (read and write values in different threads), and this is done, among the others, in the following ways:

至于 WebWorkers,它们是JavaScript API,让开发人员可以控制多线程进程。
因此,它们提供了处理对共享内存的并发访问(在不同线程中读取和写入值)的显式方法,并且可以通过以下方式完成:

  • you push data to a web worker (which means that the new thread reads data) by structured clone: The structured clone algorithm - Web APIs | MDN. Essentially there is no "shared" variable, instead the new thread is given a fresh copy of the object.
  • you push data to a web worker by transferring ownership of the value: Transferable - Web APIs | MDN. This means that the just one thread can read its value at any time.
  • as for the results returned by the web workers (how they "write"), the main thread access the results when prompted to do so (for instance with the instruction thisWorker.onmessage = function(e) {console.log('Message ' + e.data + ' received from worker');}). It must be by means of the usual Event Loop, I must suppose.
  • the main thread and the web worker access a truly shared memory, the SharedArrayBuffer, which is thread-safely accessed using the Atomicfunctions. I found this clearly exposed in this article: JavaScript: From Workers to Shared Memory
  • note: webworkers cannot access the DOM, which is truly shared!
  • 您通过结构化克隆将数据推送到网络工作者(这意味着新线程读取数据):结构化克隆算法 - Web API | MDN。本质上没有“共享”变量,而是为新线程提供了对象的新副本。
  • 你通过转移价值的所有权将数据推送给网络工作者:Transferable - Web APIs | MDN。这意味着只有一个线程可以随时读取其值。
  • 至于网络工作者返回的结果(他们如何“写”),主线程在提示时访问结果(例如使用指令thisWorker.onmessage = function(e) {console.log('Message ' + e.data + ' received from worker');})。我必须假设它必须通过通常的事件循环。
  • 主线程和网络工作者访问真正共享的内存 ,SharedArrayBuffer使用Atomic函数可以线程安全地访问它。我在这篇文章中清楚地发现了这一点:JavaScript: From Workers to Shared Memory
  • 注意:webworkers 无法访问 DOM,真正共享!

回答by JKing

You spawn a .js file as a "worker", and it runs processes in a separate thread. You can pass JSON data back and forth between it and the "main" thread. Workers don't have access to certain things like the DOM, though.

您生成一个 .js 文件作为“工人”,它在单独的线程中运行进程。您可以在它和“主”线程之间来回传递 JSON 数据。但是,Worker 无权访问某些东西,例如 DOM。

So if, say, you wanted to solve complicated math problems, you could let the user enter things into the browser, pass those variables off to the worker, let it do the computation in the background while in the main thread you let the user do other things, or show a progress bar or something, and then when the worker's done, it passes the answer back, and you print it to the page. You could even do multiple problems asynchronously and pass back the answers out of order as they finish. Pretty neat!

因此,如果您想解决复杂的数学问题,您可以让用户在浏览器中输入内容,将这些变量传递给工作人员,让它在后台进行计算,而在主线程中让用户执行其他的东西,或者显示一个进度条什么的,然后当工人完成后,它把答案传回去,你把它打印到页面上。你甚至可以异步地做多个问题,并在他们完成时不按顺序传回答案。挺整洁的!

回答by rapadura

The browser kicks of a thread with the javascript you want to execute. So its a real thread, with this web workers thing, your js is no longer single-threaded.

浏览器使用您要执行的 javascript 启动一个线程。所以它是一个真正的线程,有了这个网络工作者,你的 js 不再是单线程的。