从数据读取器异步返回数据

本文关键字:数据 返回 异步 读取 | 更新日期: 2023-09-27 18:06:17

我是新的异步的东西,我有很多问题试图让这个工作:

我试图从SQL加载一个大的结果集,我想要发生的是当我运行下面的代码:

public async override IEnumerable<DataResult> Read()
{
    using (SqlConnection objConn = new SqlConnection(Options.GetConnectionString()))
    {
        await objConn.OpenAsync();
        SqlCommand comm = new SqlCommand(Options.SqlText, objConn);
        SqlDataReader reader = await comm.ExecuteReaderAsync();
        while (await reader.ReadAsync())
            yield return new DataResult { Reader = reader };
    }
}

生产商代码:

BlockingCollection<DataResult> DataCollection = new BlockingCollection<DataResult>();
var producer = new Producer<DataResult>(() =>
{
    using (var sequenceEnum = sourceEngine.Read().GetEnumerator())
    {
        while (sequenceEnum.MoveNext())
            return sequenceEnum.Current;
    }
    return null;
}, DataCollection);
producer.Start();

它在一条记录一条记录地读取数据时将数据返回给生产者,生产者将这些数据存储在BlockingCollection中供消费者使用。

我怎样才能让这段代码为我所期望的工作?

从数据读取器异步返回数据

您的Read签名不是异步的:

public override IEnumerable<DataResult> Read();

这个方法的任何实现都必须是同步的。所以你可以只使用yield来实现它,而不使用async/await

如果您想要异步,将Read更改为ReadAsync:

public override Task<IEnumerable<DataResult>> ReadAsync();

,可以通过(异步)读入一个列表,然后返回该列表来实现。

然而,如果你真正想要的是一个异步序列(处理每一部分数据),那么你应该使用Rx:
public override IObservable<DataResult> Read();

不幸的是,您不能从async方法中yield。将其标记为async,您需要返回void, TaskTask<T>,这可以防止在方法体中生成任何yield

您可以返回IEnumerable<Task<T>>,返回您以前等待的所有内容,而不是使用await(您将无法在此方法中使用async/await)。