编辑:找到了答案-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在上下文切换中暂时暂停迭代上下文时,当我访问共享资源时,可能出现这种情况。
答案 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)。然后可以并发访问它,并且并发访问的所有效果都适用(但是您很少使用它,所以...)。