如何在后台异步读取流中的数据

时间:2015-07-07 11:52:48

标签: c# asynchronous stream

我想异步读取流(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函数不是一个好主意,但在这里我不希望调用者等待结果,我想在一些数据可用时通知它。

做出类似事情的好方法是什么?

2 个答案:

答案 0 :(得分:1)

让方法返回Task以避免async void。如果您愿意,可以忽略该任务,但最终您可能希望等待它完成。

还处理错误。现在他们被扔掉了,阅读停止了。你永远不会以这种方式找到错误。

将所有内容包装在Task.Run中,以确保此异步方法确实异步完全运行。现在,如果每个await立即完成,此方法将永远不会返回或不会在很长时间内返回。不要冒这个风险。或者,您可以将await Task.Yield();放在方法的第一行。

答案 1 :(得分:1)

WinForms仅被视为用于GUI事件处理程序。在async中,事件具有void类型的所有委托类型。通常,在使用async时,您希望在完成后以异步方式通知调用方。 .NET消息循环在此处被视为例外,因为您没有使用async/await的可能性。

在您的情况下,Invoke关键字没有多大意义。我建议您使用TaskThreadPool(或BackgroundWorker)来调用您的方法。

您没有要以异步方式作出反应的长时间运行的任务,而是一个并行的后台任务,应该这样使用。

async / await的想法是方法的调用者在方法调用之后继续,并且可以在稍后等待的方法内执行代码。但是这需要你在calling-method中使用await,这会阻塞你的主线程。

长话短说:你没有其他机会使用第二个线程并使用线程同步。

delegate就是将byte[]放入消息循环读取和执行的队列中。在您的情况下,您可以执行类似的操作:获取读取数据,如async/await并将其放入队列(通过事件)。每当你的主线程希望做一些工作时,他就从队列中抓取一个项目。 这是一种选择。这个问题的最佳解决方案很大程度上取决于您的应用程序,并且只要您没有告诉我们有关设计的更多详细信息,我就不能推荐最好的方式。但{{1}}不会是它。当然。