0

我编写了两个递归函数,对数组中的数字求和。它们做同样的事情,一个是异步的,另一个是同步的。异步函数9倍同步器完成的时间。

异步函数不应该利用同时运行更多任务的事实吗?

功能

//对数组中的数字进行异步求和异步函数sumAsync(arr){如果(arr.length==1),则返回arr[0];常数一半=arr.length/2;//左半部分的数字左常量=arr.filter((e,i)=>{返回i<一半;});//右半部分的数字右常数=arr.filter((e,i)=>{返回i>=一半;});//递归调用const leftR=sumAsync(左);const rightR=sumAsync(右);//等待解决wait Promise.all([leftR,rightR]);返回等待左R+等待右R;}//对数组中的数字进行同步求和函数sumSync(arr){如果(arr.length==1),则返回arr[0];常数一半=arr.length/2;//左半部分的数字const left=arr.filter((e,i)=>{返回i<一半;});//右半部分的数字右常数=arr.filter((e,i)=>{返回i>=一半;});//递归调用const leftR=sumSync(左);const rightR=sumSync(右);return leftR+rightR;}

测试它们

(异步()=>{常量长度=1048576;//1024^2const arr=Array.from(数组(长度),num=>Math.random()*10|0);//arr[1048576]<-随机(0~9)//异步和console.log('ASYNC');before=日期.now();log(`SUM:${await-sumAsync(arr)}`);after=Date.now();console.log(`TIME:${after-before}ms`);//同步总和console.log('SYNC');before=日期.now();console.log(`SUM:${sumSync(arr)}`);after=Date.now();console.log(`TIME:${after-before}ms`);})();

结果

//ASYNC公司//金额:4720832//时间:5554 ms//同步//金额:4720832//时间:613 ms

2个答案2

重置为默认值

的返回值异步函数始终是Promise,即使该函数只执行同步操作等待(或.然后)Promise只会在微任务期间(在当前同步代码完成运行后)运行以下内容。对于大型数组,这将导致许多不必要的微任务包装同步代码。

什么时候都没有实际的异步正在进行,这只是额外的负担,导致需要额外的处理时间和功率。

异步函数不应该利用同时运行更多任务的事实吗?

Javascript是单线程的,即使异步功能。如果一次调用多个异步函数代码路径可能在任何时候都是“活动的”。如果在标准Javascript中,所有任务所需的总处理时间都是1000毫秒,那么就不可能花费至少1000毫秒。

实际上,您并没有同时运行更多的任务——您只是在做相同的工作时,将任务包装在Promises中(不必要)。

对于真正的并行操作,您必须使用当前环境提供的某些功能,例如子进程(_P)在节点中,或网络工作者.

4
  • 你称之为“打上钩“这里?
    – 凯伊多
    评论 2020年2月22日2:12
  • 我认为这将是一个比“microtask”更直观的词,它不会立即运行,而是在当前运行的代码完成之后。这也是Node所说的差不多一样到一个微任务。 评论 2020年2月22日2:23
  • 不幸的是,这在我的脑海中有点误导,因为“tick”通常用于描述事件循环的完整迭代,而实际上它根本不是。微任务将运行立即在解决问题的任务结束后。因此,如果您的任务以这个Promise解析结束,那么它实际上是同步运行的。
    – 凯伊多
    评论 2020年2月22日2:29
  • 1
    是的,我明白你的意思。想法来自process.nextTick(回调),但对于运行的东西来说,这个名字真的很奇怪回调马上就到了,之前下一个刻度 评论 2020年2月22日3:03
2

简而言之:异步一次只做一件事。它在队列中的任务之间切换(每个切换都有开销),当一个任务阻塞时,它将控制权交给另一个任务(交换机有开销,当阻塞的任务解除阻塞时重新排队)。

长版本:异步并不意味着平行处理,这意味着交错的(并行、协作)处理。即使使用异步,JavaScript仍然是单线程的,您所做的所有实际工作都是纯CPU绑定的。事实上,您唯一真正的并发性是,异步代码将重复调度、暂停和恢复递归调用(但仍然一次只处理一个调用),而同步代码将尽可能快地按顺序执行这些调用,而不涉及事件循环。

异步代码的好处是,当执行阻塞I/O(包括等待用户输入等内容)时,该任务可以暂停,直到某个带外信号(I/O完成、用户单击鼠标等)解除阻塞,其他任务可以运行。这样做的好处是在大多数任务大部分时间都在等待某些东西的情况下,可以获得并发(但不是并行)处理的好处,因此少数准备好运行的任务可以立即开始运行(因为它们通常不运行,所以任务切换的开销并不重要;大多数时候,没有什么可以切换的,所以当你没有更好的事情要做时,会支付很多管理费用)。但它的开销肯定比不停顿地进行数字运算要高。

你的答案

单击“发布您的答案”,表示您同意我们的服务条款并确认您已阅读我们的隐私政策.

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.