我想异步读取流(serial,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();
我不确定做这样的事情是个好主意。我读到使用asynchonous void函数不是一个好主意,但在这里我不希望调用者等待结果,我想在一些数据可用时通知它。
做出类似事情的好方法是什么?
答案 0 :(得分:1)
让方法返回Task
以避免async void
。如果您愿意,可以忽略该任务,但最终您可能希望等待它完成。
还处理错误。现在他们被扔掉了,阅读停止了。你永远不会以这种方式找到错误。
将所有内容包装在Task.Run
中,以确保此异步方法确实异步完全运行。现在,如果每个await
立即完成,此方法将永远不会返回或不会在很长时间内返回。不要冒这个风险。或者,您可以将await Task.Yield();
放在方法的第一行。
答案 1 :(得分:1)
WinForms
仅被视为用于GUI事件处理程序。在async
中,事件具有void类型的所有委托类型。通常,在使用async
时,您希望在完成后以异步方式通知调用方。 .NET消息循环在此处被视为例外,因为您没有使用async/await
的可能性。
在您的情况下,Invoke
关键字没有多大意义。我建议您使用Task或ThreadPool(或BackgroundWorker)来调用您的方法。
您没有要以异步方式作出反应的长时间运行的任务,而是一个并行的后台任务,应该这样使用。
async / await的想法是方法的调用者在方法调用之后继续,并且可以在稍后等待的方法内执行代码。但是这需要你在calling-method中使用await,这会阻塞你的主线程。
长话短说:你没有其他机会使用第二个线程并使用线程同步。
delegate
就是将byte[]
放入消息循环读取和执行的队列中。在您的情况下,您可以执行类似的操作:获取读取数据,如async/await
并将其放入队列(通过事件)。每当你的主线程希望做一些工作时,他就从队列中抓取一个项目。
这是一种选择。这个问题的最佳解决方案很大程度上取决于您的应用程序,并且只要您没有告诉我们有关设计的更多详细信息,我就不能推荐最好的方式。但{{1}}不会是它。当然。