非阻塞异步代码应该使用相同数量的内存,因为在执行异步调用之前调用堆栈应该会被保存在某个地方(毕竟上下文是保存的)。当
await
出现时,并不需要保存整个调用堆栈。为什么您认为需要保存整个调用堆栈?调用堆栈是延续的具体表示,并且有待完成任务的延续不是等待的延续。等待的延续留在堆栈上。
现在,当给定调用堆栈中的每个异步方法都等待时,可能会存储与调用堆栈等效的信息在每个任务的延续中。但这些延续的内存负担是垃圾收集堆内存,而不是一百万字节已提交的堆栈内存块。延续状态大小是任务数量的n阶;线程的负担无论是否使用都是一百万字节。
如果线程在内存方面明显低效,为什么操作系统/CLR没有提供更轻量级的线程呢?操作系统确实提供了纤程。当然,纤程仍然有一个堆栈,所以也许并不更好。我想您可以使用一个小堆栈的线程。
假设我们使线程或进程更便宜。这仍然无法解决同步访问共享内存的问题。值得一提的是,如果进程更轻量级,那将是很棒的事情。但他们不是。此外,这个问题有些自相矛盾。你正在使用线程进行工作,因此你已经愿意承担管理异步操作的负担。给定的线程必须能够告诉另一个线程它已经产生了第一个线程所请求的结果。线程已经暗示了异步,但异步并不意味着线程。在语言、运行时和类型系统中构建异步架构只有对那些不得不编写管理线程代码的人有好处。
由于线程的生命周期中超过95%的时间都是休眠(在此假设为IO限制应用程序),因此性能损失应该是可以忽略不计的,因为线程的处理部分可能不会被操作系统抢占,因为它们应该非常快地运行,做很少的工作。
为什么要雇佣一个工人(线程)并支付他们的薪水来坐在邮箱旁边(让线程休眠),等待邮件到达(处理IO消息)?IO中断首先不需要线程。IO中断存在于线程以下的世界。
不要雇佣线程来等待IO; 让操作系统处理异步IO操作。雇佣线程来执行大量高延迟CPU处理,并将一个线程分配给您拥有的每个CPU。
现在我们来看看你的问题:
异步(非阻塞)代码有什么好处?
·不阻塞 UI 线程
·更容易编写在高延迟世界中运行的程序
·更有效地利用有限的CPU资源
但是让我用一个类比来重新表达这个问题。你经营着一个快递公司。有很多订单进来,很多交付出去,而你不能告诉客户说你将不接受他们的交付,直到所有之前的交付都完成。 哪种方式更好:
·雇佣50个人来接电话,取包裹,安排交货和送货,然后要求其中46个人始终处于闲置状态,
还是
雇佣四个人,让每个人一开始就变得非常优秀,一次只做一点工作,以便他们始终能够响应客户的要求,并且在将来很好地保持待办事项清单。
对我而言,后者似乎更划算。