当前位置: 首页 > 知识库问答 >
问题:

如何从头实现异步I/O绑定操作?

匡安宜
2023-03-14

我试图理解如何以及何时使用异步编程,并了解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");
}

如何实现Async版本,只使用普通的同步方法DownloadBigImage,而不使用task.run,因为这将使用线程池中的线程进行等待--这太浪费了!

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

基本上,我必须使用“p/invoke interop调用到本地网络库”...但怎么做?

共有1个答案

丁承德
2023-03-14

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

从根本上说,您不能使用任何现有的同步API。一旦它是同步的,就没有办法把它变成真正的异步。您正确地识别了task.run和它的等价物不是解决方案。

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

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

如果您认为await在练习目标方面作弊,则需要使用回调来编写此代码。这太糟糕了,所以我要写连接部分:

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

同样,这段代码非常原始,但它展示了原理。您不必等待IO完成(隐式地发生在connect内部),而是注册一个在IO完成时调用的回调。这样主线程继续运行。这就把你的代码变成了意大利面。

您需要用回调编写安全处理。这是一个问题,因为异常处理不能跨越回调。另外,如果您不想依赖框架来执行此操作,您可能需要编写一个读循环。异步循环可能会影响思维。

 类似资料:
  • 支持Python异步。包括对Core和ORM使用的支持,使用了异步兼容的方言。 1.4 新版功能. 注解 从SQLAlChemy 1.4.3开始的异步扩展现在可以被认为是 测试级 软件。API细节可能会更改,但是在这一点上,不太可能有重大的向后不兼容更改。 参见 对内核和ORM的异步IO支持 -初始功能发布 异步集成 -示例脚本演示了asyncio扩展中核心和ORM使用的工作示例。 Asyncio

  •  最大的特点就是采用异步式 I/O 与事件驱动的架构设计。对于高并发的解决方案,传统的架构是多线程模型,也就是为每个业务逻辑提供一个系统线程,通过系统线程切换来弥补同步式 I/O 调用时的时间开销。    

  • “异步”这个名词其实很早就诞生了,但它的大规模流行确实在 Web 2.0 浪潮中,它伴随着 Ajax 的第一个 A(Asnchronous)席卷了 Web。Node 在出现之前,最习惯异步编程的程序员莫过于前端工程师了。前端编程算 GUI 编程的一种,其中充斥着各种 Ajax 和事件,这些都是典型的异步应用场景。 但事实上,异步早就存在于操作系统的底层。在底层系统中,异步通信信号量、消息等方式有了

  • 传统的 Java I/O API 在应对不同的传输协议时需要使用不同的类型和方法。例如:java.net.Socket 和 java.net.DatagramSocket 它们并不具有相同的超类型,因此,这就需要使用不同的调用方式执行 socket 操作。 这种模式上的不匹配使得在更换一个网络应用的传输协议时变得繁杂和困难。由于(Java I/O API)缺乏协议间的移植性,当你试图在不修改网络传

  • 实时的web特性通常需要为每个用户一个大部分时间都处于空闲的长连接. 在传统的同步web服务器中,这意味着需要给每个用户分配一个专用的线程,这样的开销是十分巨大的. 为了减小对于并发连接需要的开销,Tornado使用了一种单线程事件循环的方式. 这意味着所有应用程序代码都应该是异步和非阻塞的,因为在同一时刻只有一个操作是有效的. 异步和非阻塞这两个属于联系十分紧密而且通常交换使用,但是它们并不完全

  • NumPy I/O操作 使用genfromtxt导入数据 定义输入 将行拆分为列 delimiter参数 autostrip参数 comments参数 跳过直线并选择列 skip_header和skip_footer参数 usecols参数 选择数据的类型 设置名称 names参数 defaultfmt参数 验证名称 调整转换 converters参数 使用缺失值和填充值 missing_valu