REST API 中的 Thread.sleep 与 Task.delay
Posted
技术标签:
【中文标题】REST API 中的 Thread.sleep 与 Task.delay【英文标题】:Thread.sleep vs Task.delay in rest api 【发布时间】:2019-10-02 19:24:09 【问题描述】:我在比较 Thread.sleep 和 task.delay。从 db 检查作业完成状态。该作业将由其他一些 Azure 组件执行。
为了测试它,创建了具有同步和异步模式的小 api。
http rest api 使用异步:
public async Task<HttpResponseMessage> Post()
await Task.Delay(200);
return await Task.FromResult(new HttpResponseMessage());
http rest api 使用同步:
public HttpResponseMessage Post()
Thread.sleep(200);
return new HttpResponseMessage();
有趣。结果对同步调用很好。使用 Apache jmeter 对 100 个用户进行了 5 次迭代。
同步结果:最小:414 毫秒,平均:8464 毫秒
异步结果:最小 1756 毫秒平均:10044 毫秒
为什么 Thread.sleep 比 Async 更好。这是任务创建的开销吗?难道我不能得到比这两个更好的结果吗?
【问题讨论】:
async
并非旨在降低延迟 - 周围有很多基础设施,因此与更多“裸机”调用相比,延迟更高是可以预期的。顺便说一句,目前还不清楚“更好的结果”是什么意思。
您可以将代码简化如下:return new HttpResponseMessage();
- 不需要await Task.FromResult
【参考方案1】:
异步代码的重点不是提高单个操作的性能。事实上,如您所见,有时情况恰恰相反。
异步代码的要点是不锁定当前线程。好处取决于应用程序的类型:
桌面应用(我知道这不适用于您,但值得一提)
在桌面应用程序中,您不会冻结 UI 线程。这样,您的 UI 在您等待来自某些 I/O 操作的响应时仍能响应用户。
因此,虽然单个操作可能需要稍微更长的时间,但用户不会因为 UI 未冻结而感到沮丧。
网络应用
在 Web 应用程序中,它释放当前线程以处理传入的下一个请求。ASP.NET 可以使用的线程数量有限,因此如果您的流量足够繁忙,请求可能需要等待在被处理之前。异步代码可以帮助您避免这种情况。
例如,同步 I/O 操作将锁定当前线程(如Thread.Sleep
)。在操作完成之前,线程不能做任何其他事情。
如果您使用异步代码(如Task.Delay
),那么一旦该异步操作开始,该线程将返回到线程池,并可用于在等待时处理另一个请求。
因此,虽然单个操作可能需要稍微更长的时间,但它可以让您的应用程序处理更大的负载。
微软在这方面的文档实际上非常出色:Asynchronous programming with async and await
【讨论】:
异步代码的要点是异步执行某些东西,这不是严格预测的顺序。它可以释放线程,也可以是单线程的。异步 I/O 的重点是将 I/O 操作卸载到某些基础设施以释放 CPU 资源,但这只是异步代码适用性的一个示例。而Thread.Sleep
与I/O无关。
" 而Thread.Sleep
与 I/O 无关。" - 是的,我知道。但在这个问题中,Thread.Sleep
和 Task.Delay
被用作同步和异步 I/O 操作的占位符。为此,它们起作用。
不,它们没有,因为它们与底层的 I/O 操作具有完全不同的性质,因此测试它们作为 I/O 的替代是不公平的,并且以这种方式对待它们。跨度>
这不是完美的替代品,不。但根据我的经验,它们在观察异步函数和非异步函数的行为方式之间的差异方面非常有用。这个问题就是一个很好的例子。
这不是真的,好像我们专门讨论 I/O 操作(不仅仅是广泛的异步操作),那么使用异步 I/O 的主要目标是可伸缩性。并且这种质量属性的差异(在同步与异步的情况下)是不可测量的,并且在使用任何异步 I/O 替代的情况下是不可观察的。因此,尽管它们可以用于衡量除可销售性之外的任何其他差异,但它们可以被替代,但正如您所说,它们是 I/O 的占位符,这种衡量至少不公平,最坏的情况是无用。以上是关于REST API 中的 Thread.sleep 与 Task.delay的主要内容,如果未能解决你的问题,请参考以下文章
C#中的Task.Delay()和Thread.Sleep()区别
Thread.sleep() 和 Thread.yield() 区别
BackgroundWorker 中的 Thread.Sleep(0) [重复]