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

本文关键字:数据 读取 异步 后台 | 更新日期: 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();放在方法的第一行。