gpt4 book ai didi

c# - IAsyncResult 与线程池

转载 作者:可可西里 更新时间:2023-11-01 08:05:07 24 4
gpt4 key购买 nike

我最近刚接触到 IAsyncResult 并且已经使用了很长时间。我真正想知道的是,当我们有更好的替代 ThreadPool 方法时,为什么还要使用 IAsyncResult?从我目前对两者的理解来看,我几乎在所有情况下都会选择使用 ThreadPool。所以我的问题是,是否存在 IAsyncResult 优于另一个的上下文?

为什么我不喜欢 IAsyncResult:

  • 增加了 BeginXXX 和 EndXXX 的复杂性
  • 如果调用者不关心返回值,他可能会忘记调用 EndXXX
  • API 设计中的冗余增加(我们需要创建 Begin 和 End 包装器方法对于我们想要异步运行的每个方法)
  • 可读性降低

把它放在代码中:

线程池

  public void ThreadPoolApproach()
{
ThreadPool.QueueUserWorkItem( ( a ) =>
{
WebClient wc = new WebClient();
var response = wc.DownloadString( "http://www.test.com" );
Console.WriteLine( response );
} );
}

IAsyncResult

  public void IAsyncResultApproach()
{
var a = BeginReadFromWeb( ( result ) =>
{
var response = EndReadFromWeb( result );
Console.WriteLine( response );
}, "http://www.test.com" );
}

public IAsyncResult BeginReadFromWeb( AsyncCallback a, string url )
{
var result = new AsyncResult<string>( a, null, this, "ReadFromFile" );

ThreadPool.QueueUserWorkItem( ( b ) =>
{
WebClient wc = new WebClient();
result.SetResult( wc.DownloadString( url ) );
result.Complete( null );
} );

return result;
}

public string EndReadFromWeb( IAsyncResult result )
{
return AsyncResult<string>.End( result, this, "ReadFromFile" );
}

最佳答案

不,您的两个代码片段之间存在巨大差异。两者实际上都使用线程池,第一个当然是明确地使用它。第二个以不太明显(和损坏)的方式执行它,IAsyncResult 回调在线程池线程上执行。

线程池是一种共享资源,在大型程序中,TP 线程有很多用途。不仅在您自己的代码中显式使用它们,.NET Framework 也使用它们。在线程池上运行的代码类型的指导是它是快速执行的代码,并且不会进行任何将 TP 线程置于等待状态的阻塞调用。阻塞是以一种非常低效的方式使用非常昂贵的操作资源,并破坏可能正在使用 TP 线程的其他代码。线程池的一个重要部分是调度器,它试图将执行 TP 线程的数量限制为机器可用的 CPU 内核数量。

但是阻塞正是您在第一个片段中所做的。 WebClient.DownloadString() 是一种非常慢的方法,无法比您的 Internet 连接或线路另一端的服务器允许的速度更快地完成。实际上,您可能会占用 TP 线程分钟。根本不做任何工作,它一直在等待 Socket.Read() 调用完成。有效的 CPU 内核利用率最多只有几个百分点。

当您使用 BeginXxxx() 或 XxxxAsync() 方法时,这有很多的不同。它在内部实现为一段代码,要求操作系统启动 I/O 操作。只需几微秒。操作系统将请求传递给设备驱动程序,在 DownloadStringAsync() 的情况下为 TCP/IP 堆栈。它作为数据项在 I/O 请求队列中的位置。您的电话很快就会回电。

最终,您的网卡从服务器获取数据,驱动程序完成 I/O 请求。通过几个层,让 CLR 获取另一个 TP 线程并运行您的回调。无论您对数据做什么,您都可以快速完成一些通常也需要几微秒的处理步骤。

请注意区别,您的第一个代码占用 TP 线程分钟,异步版本占用线程微秒。异步版本扩展更好,能够处理许多 I/O 请求。

代码的异步版本的一个重要问题是更难正确编写。同步版本中的局部变量需要成为异步版本中类的字段。它也更难调试。这就是 .NET 获得 Task 类的原因,该类后来进一步扩展,支持 C# 和 VB.NET 语言中的 async/await 关键字。

关于c# - IAsyncResult 与线程池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21278602/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com