我正在使用一些不返回詳細程度的API,因此我需要在第一次調用後進行其他API調用以獲取所需的詳細信息。我試圖通過多線程的附加調用來提高性能。下面是代碼的簡化版本我目前:無法獲得多個併發API調用來持續更新響應對象
public class Customer
{
public int CustomerId { get; set; }
public string CustomerName { get; set; }
}
public class Order
{
public int OrderId { get; set; }
public string ShippingAddress { get; set; }
}
public class OrderPayment
{
public int OrderId { get; set; }
public bool PaymentIsComplete { get; set; }
}
public class OrderItem
{
public int OrderItemId { get; set; }
public string ItemName { get; set; }
public int CustomerId { get; set; }
public int OrderId { get; set; }
}
public class OrderItemWithDetails : OrderItem
{
public Customer Customer { get; set; }
public Order Order { get; set; }
public OrderPayment Payment { get; set; }
}
public async Task<List<OrderItemWithDetails>> GetOrderItemsWithDetailsAsync()
{
var url = "orderItemsUrl";
var tuple = await GetAsync<List<OrderItemWithDetails>>(url, null, null, null);
List<OrderItemWithDetails> response = tuple.Item1;
List<Task> taskList = new List<Task>();
IEnumerable<int> customerIds = response.Select<OrderItemWithDetails, int>(o => o.CustomerId).Distinct();
foreach (var customerId in customerIds)
{
int id = customerId;
taskList.Add(Task.Run(async() =>
{
url = "customerUrl?CustomerId=" + id;
var customerTuple = await GetAsync<Customer>(url, null, null, null);
response.Where(i => i.CustomerId == id).ToList().ForEach(i => i.Customer = customerTuple.Item1);
}));
}
IEnumerable<int> orderIds = response.Select<OrderItemWithDetails, int>(o => o.OrderId).Distinct();
foreach (var orderId in orderIds)
{
int id = orderId;
taskList.Add(Task.Run(async() =>
{
url = "orderUrl?OrderId=" + id;
var orderTuple = await GetAsync<Order>(url, null, null, null);
response.Where(i => i.OrderId == id).ToList().ForEach(i => i.Order = orderTuple.Item1);
}));
taskList.Add(Task.Run(async() =>
{
url = "paymentUrl?OrderId=" + id;
var paymentTuple = await GetAsync<OrderPayment>(url, null, null, null);
response.Where(i => i.OrderId == id).ToList().ForEach(i => i.Payment = paymentTuple.Item1);
}));
}
await Task.WhenAll(taskList);
return response;
}
的GetAsync基本上是圍繞HttpClient.GetAsync一個包裝與一些額外的邏輯,包括處理解析JSON轉換成一個對象。我知道該電話中的代碼很好,它已被用於一些其他2年以上的電話。我一直遇到的兩個問題是,它不會等待任務完成,因此OrderItemWithDetails中的其他對象不會一致地填充,並且偶爾Task.WhenAll會在IEnumerable上引發異常,該異常不能爲null。我曾經嘗試過的以下更改每一個組合,一些工作更穩定比別人,但他們沒有工作時間的100%:
- 變化Task.Run到Task.Factory.StartNew
- 更改匿名方法不能異步和更改的await GetAsync到GetAsync.Result
- 變化Task.WhenAll到Task.WaitAll
- 使用ContinueWith並在GetAsync另一個匿名方法調用來處理更新響應對象
- 構建創建任務之前的url,改變匿名方法直接指向GetAsync,並在所有任務運行後將結果添加到響應中
- 創建一個單獨的「狀態」列表,在每個任務向狀態「NotDone」添加條目之前添加一行每個任務的最終更新狀態爲任務「完成」,並與其中循環,等待列表中的所有條目將被「完成」
即使更換Taks.WhenAll我知道的最後一個選項是修復這個問題的完全錯誤的方法並不奏效(仍然以響應中的一堆空屬性結束),這完全讓我感到困惑。我已經爲此工作了好幾天了,Google已經瘋狂了,並且仍然沒有接近正常工作的代碼。任何幫助將非常感激。