I Have a scenario in which I am reading some data from a database. This data is returned in the form of IAsyncEnumerable<MyData>
. After reading the data I want to send it to a consumer. This consumer is asynchronous. Right now my code looks something like this:
// C#
IAsyncEnumerable<MyData> enumerable = this.dataSource.Read(query);
await foreach (var data in enumerable)
{
await this.consumer.Write(data);
}
My problem with this is that while I am enumerating the database, I am holding a lock on the data. I don't want to hold this lock for longer than I need to.
In the event that the consumer is consuming data slower than the producer is producing it, is there any way I can eagerly read from the datasource without just calling ToList
or ToListAsync
. I want to avoid reading all the data into memory at once, which would cause the opposite problem if now the producer is slower than the consumer. It is ok if the lock on the database is not as short as possible, I want a configurable tradeoff between how much data is in memory at once, and how long we keep the enumeration running.
My thought is that there would be some way to use a queue or channel-like datastructure to act as a buffer between the producer and consumer.
In Golang I would do something like this:
// go
queue := make(chan MyData, BUFFER_SIZE)
go dataSource.Read(query, queue)
// Read sends data on the channel, closes it when done
for data := range queue {
consumer.Write(data)
}
Is there any way to get similar behavior in C#?