es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Escribir de forma asíncrona a un IAsyncEnumerable.

Estoy utilizando IAsyncEnumerable para devolver resultados paginados de una API a medida que llegan, de la siguiente manera:

public async IAsyncEnumerable GetResults(){
int startIndex = 0;
PaginatedResponse response;
do {
response = await _client.GetResults(_endpoint, startIndex, _pageSize);
foreach (var obj in response.Items){
yield return obj;
}
startIndex = response.StartIndex + response.Count;
} while (response.StartIndex + response.Count < response.Total);
}

Lo que quiero es enviar solicitudes para varias páginas en paralelo y devolver cada página a IAsyncEnumerable a medida que llega. El orden no importa.

¿Es posible lo que intento hacer? ¿Puedo tener varias tareas asíncronas escribiendo en el mismo IAsyncEnumerable que mi método devuelve? Lo mejor que se me ocurre es tener las tareas escribir en un IList común, y luego, después de que todas las tareas estén completas, iterar sobre ese IList y devolver todos los elementos:

public async Task<IAsyncEnumerable> GetResults(){
int totalPages = _client.MagicGetTotalPagesMethod();
IList results = new List();
var tasks = Enumerable.Range(0,totalPages).Select(async x => {
// mi objetivo es devolver desde aquí, en lugar de agregarlo al IList y devolverlo después de que se completen todas las tareas
results.AddRange(await _client.GetResults(_endpoint, x*_pageSize, _pageSize));
});
await Task.WhenAll(tasks);
foreach (var result in results){
yield return result;
}
}

Esto resuelve parcialmente el problema al tener varias solicitudes activas al mismo tiempo, pero todavía tenemos que esperar a que todas regresen antes de que el consumidor de GetResults pueda usar los resultados.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    ¿Existe una mejor manera de hacer esto?

    Sí, es posible tener múltiples tareas asíncronas escribiendo en el mismo IAsyncEnumerable que devuelve su método.

    Puede usar el método Concat para combinar múltiples IAsyncEnumerable en uno y luego usar SelectMany para aplanar los resultados en un solo IAsyncEnumerable. Esto le permitirá realizar múltiples solicitudes en paralelo y devolver los resultados a medida que lleguen.

    Por ejemplo:

    public async IAsyncEnumerable<ApiObject> GetResults(){
      int totalPages = _client.MagicGetTotalPagesMethod();
      var tasks = Enumerable.Range(0,totalPages).Select(async x => {
        return await _client.GetResults(_endpoint, x*_pageSize, _pageSize);
      });
      var results = await Task.WhenAll(tasks);
      return results.SelectMany(x => x.Items).Concat();
    }
    

Comments are closed.