簡體   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