JavaScript异步与C#异步

时间:2019-05-22 21:37:51

标签: javascript c# asynchronous concurrency

编辑:找到了答案-https://www.youtube.com/watch?v=8aGhZQkoFbQ

_

好吧,所以我有一些C#背景,C#“异步环境”是并发与“ small parallelism”混合在一起的,也就是说,当涉及到繁重的异步环境时,您 可以 存在竞争条件,僵局,您需要保护共享资源。

现在,我试图了解JavaScript / ES6异步环境如何工作。考虑以下代码:

// current context: background "page"
// independent from content page
let busy = false;

// This is an event handler that receives event from content page
// It can happen at any time
runtimeObj.onMessage.addListener((request) =>
{
    if(request.action === 'AddEntry')
    {
        AddEntry(request);
        return true;
    }
    return false;
} );


function AddEntry(data)
{
    if (!busy)
        group.push({url: data.url, time: Date.now(), session: data.session});
    else
        setTimeout(AddEntry(data),10000) // simulating Semaphore wait
}

// called from asynchronous function setInterval()
function SendPOST()
{
    if (groups.length < 1 || groups === undefined)
        return;

    busy = true; // JS has no semaphores so I "simulate it"
    let del = [];
    groups.forEach(item =>
    {
        if (Date.now() - item.time > 3600000)
        {
            del.push(item);
            let xhr = new XMLHttpRequest();
            let data = new FormData();
            data.append('action', 'leave');
            data.append('sessionID', item.session);
            xhr.withCredentials = true;
            http.onreadystatechange = function()
            {
                if(http.readyState == 4 && http.status !== 200) {
                    console.log(`Unable to part group ${item.url}! Reason: ${http.status}. Leave group manually.`)
            }
}
            xhr.open('POST', item.url, true);
            xhr.send(data);
        }
    });
    del.forEach(item => groups.slice(item,1));
    busy = false;
}


setInterval(SendPOST, 60000);

这并不是最好的例子,因为它没有一堆与功能配对的async关键字,但据我了解,sendPost()AddEntry()都没有真正的顺序操作。尽管如此,有人告诉我在AddEntry()中,busy总是false,因为:

  

sendPost已排队等待一分钟执行

     

将一个事件添加到事件循环中

     

事件已处理并调用AddEntry

     

因为忙=否,群组被推送

     

一分钟过去,将SendPost添加到事件循环中

     

事件为流程,调用SendPost

     

groups.length === 1,所以它会继续

     

忙=真

     

每个组都会导致请求排队

     

一个事件进来

     

忙=假

     

事件已处理,AddEntry被调用

     

忙是虚假的,就像往常一样

     

组被推送

     

最终,来自之前的请求得到解决,并且   他在事件循环中放置了onreadystatechange回调

     

最终每个回调都得到处理并执行日志记录语句

这是正确的吗?据我了解,它本质上意味着没有竞争条件或僵局,或者我需要保护共享资源。

如果我两个人为C#运行时编写了相似的代码,其中sendPost()AddEntry()是异步任务方法,可以从不同事件以非阻塞方式调用当线程上下文由Thread Sheduler在上下文切换中暂时暂停迭代上下文时,当我访问共享资源时,可能出现这种情况。

1 个答案:

答案 0 :(得分:2)

  

这是正确的吗?

是的,它充分描述了正在发生的事情。

JS以单线程方式运行,这意味着一个函数将一直运行到结束。

 setTimeout(function concurrently() {
   console.log("this will never run");
 });

  while(true) console.log("because this is blocking the only thread JS has");
  

可能没有比赛条件...

可以(以逻辑方式)。但是,它们不能出现在同步代码中,因为JavaScript运行单线程¹。如果您在某物上添加了回调或await承诺,则其他代码可能会在平均时间中运行(但不能同时),这会可能会导致比赛状况:

 let block = false;

 async function run() {
   if(block) return // only run this once
   // If we'd do block = true here, this would be totally safe
   await Promise.resolve(); // things might get out of track here
   block = true;
   console.log("whats going on?");
}

run(); run();
  

...也没有死锁...

是的,它们是完全不可能的(除非您使用Atomics¹)。

  

我永远不需要保护共享资源。

是的。因为没有共享资源(可以,除了SharedBuffers¹)。


¹:通过使用WebWorkers(或NodeJS上的线程),您实际上控制了多个JS线程。但是,每个线程都运行自己的JS代码,因此不会共享变量。这些线程可以在彼此之间传递消息,也可以共享特定的内存构造(SharedArrayBuffer)。然后可以并发访问它,并且并发访问的所有效果都适用(但是您很少使用它,所以...)。