Task.WhenAll 与 LINQ select

Task.WhenAll with LINQ select

long[] orderIds={10,11,12,13};

var orders= new List<Order>();

await Task.WhenAll(orderIds.Select(async (orderId) =>
{
    var orderDetails = await GetOrderDetails(orderId);

    if (orderDetails != null)
        orders.Add(orderDetails);
}));

我遇到了一些错误的行为,在将此代码部署到服务器后它工作正常但在本地有时它会添加所有订单但有时它会错过一些订单。

任何人都可以帮助缩短这个,不知道我错过了什么。

我想锁就可以了。

long[] orderIds={10,11,12,13};

var orders= new List<Order>();

await Task.WhenAll(orderIds.Select(async (orderId) =>
{
    var orderDetails = await GetOrderDetails(orderId);

    if (orderDetails != null)
        lock(orders) orders.Add(orderDetails);
}));

您应该使用 Microsoft 的 Reactive Framework(又名 Rx)- NuGet System.Reactive 并添加 using System.Reactive.Linq; - 然后您可以这样做:

long[] orderIds = { 10, 11, 12, 13 };

IList<Order> orders = await
    orderIds
        .ToObservable()
        .SelectMany(id => Observable.FromAsync(() => GetOrderDetails(id)))
        .ToList();

首先,我建议在将任务发送到任何地方之前强制枚举任务(例如额外的 ToList() 调用)。您不希望不小心多次枚举列表。

var tasks = orderIds.Select( orderId => GetOrderDetails(orderId) ).ToList();

然后等待任务:

await Task.WhenAll( tasks );

瞧,你的订单已经准备好了。

var orders = tasks.Select( t => t.Result ).Where( o => o != null ).ToList();

顺便说一句,没有任何东西被改变,所以你是完全线程安全的,不需要任何锁(假设 GetOrderDetails 是线程安全的)。这是 advantages of a functional approach 使用 linq 和一般的方法之一。