如何在后台异步读取流中的数据
本文关键字:数据 读取 异步 后台 | 更新日期: 2023-09-27 18:01:18
我想从流(串行,tcp,无论什么)异步读取数据,并触发事件通知其他组件。
下面是伪代码,假设"stream"是一个有效的流
public class Reader {
private _stream;
private _buffer = new bytes[4096];
public event Action<byte[], int> DataRecieved;
public async void StartReading() {
while (true) {
var nbytes = await _stream.ReadAsync(_buffer, 0, _buffer.Length);
if (nbytes == 0)
return;
var handlers = DataRecieved;
if (handlers != null)
DataRecieved(_buffer, nbytes);
}
}
}
调用者部分:
var r = new Reader();
r.OnDataRecieved += myHandler;
r.StartReading();
我不确定这样做是个好主意。我读到使用异步void函数不是一个好主意,但在这里我不希望调用者等待结果,我想在一些数据可用时通知它。
怎么做呢?
void async
仅被认为用于GUI事件处理程序。在WinForms
中,事件具有类型为void的所有委托类型。通常,当使用async
时,您希望在完成时以异步方式通知调用者。. net消息循环在这里被认为是例外,因为您没有使用async
的不同可能性。
在您的例子中,async/await
关键字没有多大意义。我建议使用Task或ThreadPool(或BackgroundWorker)调用您的方法。
您不希望以异步方式对长时间运行的任务进行响应,而是应该使用并行后台任务。
async/await的思想是方法的调用者在方法调用后继续,并可能在等待之后执行方法内部的代码。但是这需要你在调用方法中使用await,这会阻塞主线程。
长话短说:你没有其他机会使用第二个线程和使用线程同步。
Invoke
只不过是将delegate
放在消息循环读取并执行的队列中。在您的情况下,您可以做类似的事情:获取读数据,如byte[]
,并将其放入队列中(通过事件)。每当主线程想要做一些工作时,它就从队列中抓取一个项目。这是一种选择。这个问题的最佳解决方案在很大程度上取决于您的应用程序,由于您没有告诉我们有关设计的更多细节,我无法推荐最佳的方法。但async/await
不会是它。肯定。
使方法返回Task
以避免返回async void
。如果您愿意,可以忽略该任务,但最终您可能希望等待它完成。
也处理错误。现在,它们被扔掉了,阅读静静地停止了。这样你永远也找不到bug。
将所有内容包装在Task.Run
中,以确保此异步方法确实完全异步运行。现在,如果每个await
立即完成,这个方法将永远不会返回或在很长一段时间内不返回。不要冒这个险。或者,您可以将await Task.Yield();
放在方法的第一行。