c# – 如何从头开始实现异步I / O绑定操作?

前端之家收集整理的这篇文章主要介绍了c# – 如何从头开始实现异步I / O绑定操作?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我试图了解如何以及何时使用异步编程并进行I / O绑定操作,但我不理解它们.我想从头开始实现它们.我怎样才能做到这一点?

考虑下面的同步示例:

private void DownloadBigImage() {
    var url = "https://cosmos-magazine.imgix.net/file/spina/photo/14402/180322-Steve-Full.jpg";
    new WebClient().DownloadFile(url,"image.jpg");
}

如何通过仅使用正常的同步方法DownloadBigImage而不使用Task.Run来实现异步版本,因为这将仅使用线程池中的线程进行等待 – 这只是浪费!

也不要使用已经异步的特殊方法!这就是这个问题的目的:如何在不依赖已经异步的方法的情况下自己制作它?所以,没有像这样的事情:

await new WebClient().DownloadFileTaskAsync(url,"image.jpg");

在这方面非常缺乏可用的示例和文档.我发现只有这个:
https://docs.microsoft.com/en-us/dotnet/standard/async-in-depth
其中说:

The call to GetStringAsync() calls through lower-level .NET libraries (perhaps calling other async methods) until it reaches a P/Invoke interop call into a native networking library. The native library may subsequently call into a System API call (such as write() to a socket on Linux). A task object will be created at the native/managed boundary,possibly using TaskCompletionSource. The task object will be passed up through the layers,possibly operated on or directly returned,eventually returned to the initial caller.

基本上我必须使用“P / Invoke互操作调用到本机网络库”……但是如何?

解决方法

我认为这是一个非常有趣的问题,也是一个有趣的学习练习.

从根本上说,您不能使用任何同步的现有API.一旦它同步,就无法将其变为真正的异步.您正确地确定了Task.Run及其等价物不是解决方案.

如果拒绝调用任何异步.NET API,则需要使用PInvoke调用本机API.这意味着您需要调用WinHTTP API或直接使用套接字.这是可能的,但我没有经验来指导你.

相反,您可以使用异步托管套接字来实现异步HTTP下载.

从同步代码开始(这是一个原始草图):

using (var s = new Socket(...))
{
 s.Connect(...);
 s.Send(GetHttpRequestBytes());
 var response = new StreamReader(new NetworkStream(s)).ReadToEnd();
}

这非常粗略地将您的HTTP响应作为字符串.

您可以使用await轻松实现真正的异步.

using (var s = new Socket(...))
{
 await s.ConnectAsync(...);
 await s.SendAsync(GetHttpRequestBytes());
 var response = await new StreamReader(new NetworkStream(s)).ReadToEndAsync();
}

如果你考虑等待你的运动目标作弊,你需要使用回调来写这个.这太糟糕了,所以我只想写连接部分:

var s = new Socket(...)
s.BeginConnect(...,ar => {
   //perform next steps here
},null);

同样,这段代码非常原始,但它显示了原理.您可以注册在IO完成时调用的回调,而不是等待IO完成(这隐式发生在Connect中).这样你的主线程继续运行.这会把你的代码变成意大利面条.

您需要使用回调编写安全处理.这是一个问题,因为异常处理不能跨越回调.此外,如果您不想依赖框架来执行此操作,则可能需要编写读取循环.异步循环可以是弯曲的.

猜你在找的C#相关文章