由于JavaScript是单线程的,HTML5中的Web worker如何进行多线程处理?

Jam*_*ard 56 javascript html5 web-worker

我一直在阅读HTML5中的Web worker,但我知道JavaScript是单线程的.

我的问题是:

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

rob*_*rtc 63

正如几条评论已经指出的那样,工人真的是多线程的.

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

  • JavaScript是一种语言,它没有定义线程模型,它不一定是单线程的
  • 大多数浏览器历史上都是单线程的(虽然这种情况正在迅速变化:IE,Chrome,Firefox),大多数JavaScript实现都发生在浏览器中
  • Web Workers不是JavaScript的一部分,它们是一种可以通过JavaScript访问的浏览器功能

  • @JamesDrinkard我认为主要问题是[DOM](http://en.wikipedia.org/wiki/Document_Object_Model)不能轻易制作多线程,而JavaScript通常用于DOM操作.但DOM不是JavaScript. (8认同)
  • 这就是我缺少区别的地方,它与浏览器规范有关,而不是JavaScript语言. (6认同)
  • @JamesDrinkard javascript*仍然是单线程*,即使是网络工作者.Web工作者不会以任何前所未有的方式创建javascript多线程,请考虑这样:您实际上是在启动另一个单线程进程并与之通信,就像您在节点中一样.例如,js.浏览器中的javascript是单线程的,worker中的javascript是单线程的,但是它们能够通过瘦通道相互通信. (2认同)

Ant*_*nio 9

有点晚了,但我问自己同样的问题,我想出了以下答案:
浏览器中的Javascript总是单线程的,一个根本的结果是对变量的"并发"访问(多线程编程的主要问题)实际上不是并发的; 这是真的与webworkers例外,这实际上是在单独的线程运行和变量的并发访问必须在几分明确的方式来处理.

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

实际上,没有必要让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++;
Run Code Online (Sandbox Code Playgroud)

counter流程结束时的价值是多少?是的2.它是"同时"读写并不重要,它永远不会导致a 1.这意味着访问counter始终是一致的.如果两个线程同时真正访问该值,它们都可以通过读取开始,最后0都写入1.

在浏览器中,远程资源的实际数据获取对开发人员是隐藏的,其内部工作在JavaScript API的范围之外(浏览器允许您根据JavaScript指令控制).就开发人员而言,网络请求的结果由主线程处理.
简而言之,实际执行请求是不可见的,但是回调的调用(由自定义JavaScript代码处理结果)由主线程执行.
可能,如果不是网络工作者,"多线程"一词将永远不会进入Javascript世界.

请求的执行和回调的异步调用实际上是通过使用事件循环而不是多线程来实现的.这对于几个浏览器来说都是如此,显然对于Node.js. 以下是一些参考文献,在某些情况下有点过时,但我想现在仍然保留了主要的想法.

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

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

  • 您通过结构化克隆将数据推送到Web工作者(这意味着新线程读取数据):结构化克隆算法 - Web API | MDN.基本上没有"共享"变量,而是为新线程提供了对象的新副本.
  • 通过转移值的所有权将数据推送到Web worker:Transferable - Web API | MDN.这意味着只有一个线程可以随时读取其值.
  • 至于Web worker返回的结果(它们如何"写"),主线程在提示时访问结果(例如使用指令thisWorker.onmessage = function(e) {console.log('Message ' + e.data + ' received from worker');}).我必须假设它必须通过通常的事件循环.
  • 主线程和Web工作者访问真正的共享内存,SharedArrayBuffer使用这些Atomic函数进行线程安全访问.我在本文中清楚地揭示了这一点:JavaScript:从工人到共享内存
  • 注意:webworkers无法访问真正共享的DOM!


JKi*_*ing 5

您将.js文件生成为"worker",并在单独的线程中运行进程.您可以在它和"主"线程之间来回传递JSON数据.但是,工作人员无法访问DOM等特定内容.

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