繁体   English   中英

任务完成时未处理

[英]Tasks not being processed as they complete

我一直试图处理大量数据库查询的结果,因为它们变得可用。 现在,它们都在同一时间处理。

有一个客户端列表(目前大约有40个),每个客户端都有其自己的数据库,需要查询所有这些客户端(使用EF-6)。 存储库上的查询方法返回一个任务。 这些任务是循环创建的。

public Task<List<Employee>> FindByNameOrBirthDateAsync(string surName, DateTime? birthDate)
    {
        var query = ApplicationContext.Employees
            .Include(e => e.Address)
            .Include(e => e.CorporateEntities);

        if (!string.IsNullOrWhiteSpace(surName))
            query = query.Where(e => e.Surname == surName);

        if (birthDate != null)
            query = query.Where(e => e.BirthDate == birthDate);

        return query.ToListAsync();
    }

该代码由服务调用,而服务又由Web-API控制器调用。

public class SearchService
{
    public List<Task<List<Employee>>> SearchOverAllClients(List<Client> clients, string surName, DateTime? birthDate)
    {
        return clients.Select(client => FindEmployees(client.Id, surName, birthDate)).ToList();
    }

    private Task<List<Employee>> FindEmployees(int clientId, string surname, DateTime? birthDate)
    {
        ApplicationUoW unit = new ApplicationUoW(clientId);

        return unit.Employees.FindByNameOrBirthDateAsync(surname, birthDate);

    }
}

在控制器中,Task.WhenAny()应该在结果可用时将结果返回给客户端,并将其写入输出流。

我已经测试了Fiddler在每次迭代中都处于中断状态,并且结果一次发送一次。 因此,我认为问题不在于编写代码的流中。

    public HttpResponseMessage Get([FromUri]string surname = "", [FromUri]DateTime? birthDate = null)
    {
        List<Client> clients = _clientsService.GetClients();
        List<Task<List<Employee>>> tasks = _searchService.SearchOverAllClients(clients, surname, birthDate);

        HttpResponseMessage response = Request.CreateResponse();

        response.Content = new PushStreamContent(
            async (outputStream, httpContent, transportContext) =>
            {
                try
                {
                    while (tasks.Count > 0)
                    {
                        var task = await Task.WhenAny(tasks);
                        tasks.Remove(task);

                        List <Employee> employees = await task;
                        string responseContent =
                            await Task.Factory.StartNew(() => JsonConvert.SerializeObject(employees, Formatting.None, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }));

                        var buffer = Encoding.UTF8.GetBytes(responseContent);

                        await outputStream.WriteAsync(buffer, 0, buffer.Length);
                        await outputStream.FlushAsync();
                    }
                }
                catch (HttpException ex) when (ex.ErrorCode == -2147023667)
                {
                    //The remote host closed the connection.
                    return;
                }
                finally
                {
                    outputStream.Close();
                }
            });

        return response;
    }

此代码的问题在于,它在处理结果之前等待所有任务完成。 我想尽快处理它们。

我一直在尝试使用aysnc / await的不同用法来对此代码进行多种变体,但是到目前为止,所有尝试均未成功。

更新我已经按照注释中的建议删除了不需要的并行代码。

我认为您正在寻找的是ConfigureAwait(false)

ASP.NET以确保async代码在整个执行过程中的任何给定时间在单个线程(但不一定是同一线程)上运行的方式实现SynchronizationContext 这意味着您现在发布的代码将全部在单个线程上运行。 因此,例如,如果所有查询任务立即完成,则var task = await Task.WhenAny(tasks)之后的回调代码将不会并行运行-每个回调将同步运行,一个接一个。

通过转换为: await Task.WhenAny(tasks).ConfigureAwait(false)您告诉.NET回调代码可以在线程池线程上运行。 但是然后,您必须确保await之后的代码是线程安全的,并且不需要上下文。

如果您还不熟悉SynchronizationContext以及为什么使用async/await时它很重要,那么我发现这篇文章对您有所帮助: Await,SynchronizationContext和Console Apps

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM