在 JavaScript 中模拟上下文切换?

Posted

技术标签:

【中文标题】在 JavaScript 中模拟上下文切换?【英文标题】:Simulating context switches in JavaScript? 【发布时间】:2011-06-22 13:41:54 【问题描述】:

我一直致力于在 javascript 中实现一个非常复杂的系统,该系统需要模拟多线程进程等。在真正的多线程进程(例如内核线程)中,可以通过上下文切换在线程之间切换。这是因为您可以将当前进程的程序计数器和寄存器存储到一个临时结构中,为其他进程恢复程序计数器和寄存器,然后从您在上一个进程中中断的地方恢复。

我很好奇是否有可能在 JavaScript 中有类似的东西。我目前不知道如何做到这一点,因此一直在使用协作多任务设计系统。特别是,我想在多线程模拟器中运行的任何“函数”都被拆分为一个 array 函数。为了执行“函数”,我遍历函数数组,按顺序执行每个函数,同时维护下一个要执行的函数的“程序计数器”。这允许我通过调用数组中的一个函数来模拟上下文切换,等待函数返回,然后切换到需要执行的其他一些函数数组。

我目前的方法可行,但在这个系统中编写代码很困难。每个函数都必须明确指出何时可以中断,并且由于数组中的函数都是独立的,因此函数不同部分之间的数据通信逻辑很复杂。我希望得到更接近抢先式多任务工作的东西。

我的问题是:是否可以通过外部源暂停和恢复任意 JavaScript 函数的方式运行它?

【问题讨论】:

当有人在同一个句子中使用 JavaScript 和多线程时,必须提到 Web Workers。 【参考方案1】:

首先,重要的是要提到 JavaScript 是完全单线程的。模拟多线程真的不是要走的路。依赖事件循环会好得多。

如前所述,可以使用网络工作者,但它们并没有真正的跨浏览器合规性,所以我将忽略网络工作者。此外,您不能对 Web Worker 进行任何 DOM 操作。

我想说看看node.js 来推理为什么事件循环是多线程的一个很好的替代方案。我相信他在video 中很好地解释了为什么它是一个不错的选择。

因此,与其拥有一组函数并对其进行迭代,不如创建一个事件并将一组函数绑定到它们并触发所述事件。在backbone.js 中可以找到一个非常轻量级的事件实现。

您不能只暂停 JavaScript 中的一个线程,因为只有一个。如果函数中没有点,就无法暂停或恢复函数。

只有一种方法可以模拟这一点。编写一个 JavaScript 解析器,将您精心构建的 JavaScript 拆分开来,并构建一个允许您暂停和恢复 JavaScript 的系统。

以这个函数为例

function(i) 
    j = i + 1;
    console.log(j);
    return foo(j);

并将其转换成这个

var bar = function(i) 
    var r = ;
    var j = i + 1; 
    var f = function() 
         console.log(j);
         var g = function() 
              return foo(j);
         ;
         onNext(g, arguments.callee, this, r);
    ;
    onNext(f, arguments.callee, this);
    return r;

您需要使用.suspend.resume 扩展函数

Function.prototype.suspend = function() 
     this.__suspended = true;


Function.prototype.resume = function() 
     this.__suspended = false;


function onNext(callback, function, context, returnObj) 
     if (!function.__suspended) 
          var cb = function() 
              Backbone.Events.unbind("run", cb);
              returnObj.r = callback.call(this);
          
          Backbone.Events.bind("run", cb);
     


setInterval(function() 
     Backbone.Events.trigger("run");
, 5);

您还必须将所有对var a = b() 的引用替换为

callFunctionAsync(b, context, args, function(return) 
    var a = return;
    ...
);

我将把实施留给你。目前所有函数都返回一个对象r,并且只有当r.r 设置为一个值时,它才会“返回”。因此,只需检查事件循环是否已“返回”,方法是检查是否设置了 r.r 以及是否触发了函数异步回调。

嘿,看看我们有什么。通过在事件循环中运行线程来模拟线程。最好在代码中本地使用事件循环,而不是通过它模拟线程。

当你再次循环事件循环时,基本上让你的函数运行下一行代码。并检查在您绕过事件循环时特定的“功能”是否被暂停或恢复。

为了简洁起见,我没有实现将函数的返回冒泡返回到“函数”。这应该不难模仿。

要么直接使用事件循环,要么使用假线程方法并让编译器编译你的代码,这样你编码时它就不会看起来很可怕。

如果你造成死锁,祝你好运。

【讨论】:

@Raynos- 感谢您的建议!我目前的实现并没有像实现需要线程的系统(特别是 JVM)那样真正使用线程,所以我在这里真的别无选择。我目前正在使用事件来执行此操作 - 我有一个窗口超时,它会定期触发以运行更多代码。您让每个函数注册一个延续的建议真的很棒——我想我可以构建一个交叉编译器来为我自动生成这个代码。非常感谢您的建议! @templatetypedef 如果您为 JVM 实现线程,为什么需要对 javascript 进行线程化?您是否让用户在您的 JVM 上运行 javascript 代码?这样做似乎很错误,而且很容易让线程出错并完全破坏状态。任何需要线程的 JVM 内部都可以使用事件循环在您的 javascript 内部实现。 @Raynos- 恰恰相反-我正在使用 JavaScript 来实现 JVM。 :-) 这是一个学术项目。挑战在于如何在 JavaScript 中最好地实现 JVM 级线程,同时允许在 JavaScript 中本地实现 Java 原生函数。 @templatetypedef 这就是你使用 JS 来模拟 JVM 的意思。为什么你需要你的 javascript 来运行线程。为什么你不能只使用一个事件循环并让你的 JVM 的低级 javascript 实现依赖于事件循环,但让你的高级 Java 代码假装它的线程但委托给事件循环。我还消除了返回值冒泡,这让我很头疼。 @Raynos- 我目前正在使用事件循环来进行解释。问题在于处理本机方法(例如,Class.forName)。此代码是用 JavaScript 编写的,但必须通过长时间不运行并阻塞主循环来与解释器配合使用。类似地,一些本机逻辑(例如,初始化一个类)必须与监视器交互,因此必须能够在某个时间暂停执行,并在稍后获得锁时恢复。因此,我渴望让先发制人的多任务处理工作。【参考方案2】:

签出StratifiedJS

【讨论】:

stratifiedjs.org 说:“StratifiedJS 使用少量关键字扩展了 JavaScript 语言,用于并发编程。它允许您以直接、结构化的顺序样式表达异步控制流。”听起来像你需要的 @qwertymk- 这看起来很棒,但不幸的是(据我所知)任何网络浏览器都不支持它,这在某种程度上违背了目的。不过,这是一个很棒的链接,我感谢您分享它! @templatetypedef 它受 Web 浏览器支持。转到their console 并尝试运行:console.log('waiting 3 seconds....'); hold(3000); console.log('done') @qwertymk- 哎呀!错过了那个链接。感谢您指出这一点!

以上是关于在 JavaScript 中模拟上下文切换?的主要内容,如果未能解决你的问题,请参考以下文章

execute as login 切换上下文

Security8:权限模拟

Security8:权限模拟

JavaScript实现屏幕上下滑动的效果?

警报处理程序中交换上下文后的分段错误

使用javascript实现图片上下切换效果并且实现顺序循环播放