我的任务列表仅运行两次,而应该运行多次

时间:2019-11-28 10:06:52

标签: c# asynchronous

我想在所有行上运行一个函数,但是我希望它可以并行运行,而不是一次为每一行运行。问题在于,它似乎只运行两次(列表中有217种产品),并且似乎随机选择了行。我不确定为什么会发生这种情况-同步版本按预期工作。

该函数对使用WPF SfDataGrid中的行数据的SOAP服务进行API调用。如此多次请求后,API可能会关闭连接?真的很难说,除了写票和等待一周外,我不知道该如何检查。

事件的一部分,从中调用该函数:

var tasks = new List<Task>();
using (var db = new SqliteConnection("Data Source=file:products.sqlite"))
{
    using (var client = new ApiOrdersPortTypeClient(binding, address))
    {
        db.Open();
        // run ScanProduct() on each row in a WPF SfDataGrid
        foreach (var row in ProductList.View.Records)
        {
            tasks.Add(Task.Factory.StartNew(
                () => ScanProduct(row, desiredDays, deliveryTime, client, db)));
        }

        Task.WaitAll(tasks.ToArray());
    }
}

ScanProduct()

private async Task ScanProduct(RecordEntry row, int desiredDays, int deliveryTime, ApiOrdersPortTypeClient client, SqliteConnection db)
{
    await db.OpenAsync();
    var selectedItem = (Product)row.Data;

    if (selectedItem.IsIgnored == true | selectedItem.IsInDelivery == true)
    {
        return;
    }
    else
    {
        var pagesCount = await ApiRequests
            .GetOrdersPages(int.Parse(selectedItem.Id), desiredDays, client);

        var listSold = await ApiRequests
            .GetOrdersFromApi(int.Parse(selectedItem.Id), desiredDays, pagesCount);
        foat x = 100.0; // cut irrelevant stuff

        if (x > selectedItem.Stock)
        {
            using (var command = 
                new SqliteCommand($"UPDATE products_settings SET requires_purchase = 1,"
                + $" was_checked_with = {desiredDays},"
                + $"sold_amount = {listSold.Count}," 
                + $"average_daily = '{averageSales.ToString()}',"
                + $"average_delivery = '{x}'"
                + $"WHERE id = {selectedItem.Id};", db))
                {
                    await db.OpenAsync();
                    command.ExecuteReader();
                }
        } 
        else
        {
            using (var command2 = 
                new SqliteCommand($"UPDATE products_settings SET requires_purchase = 0,"
                + $"was_checked_with = {desiredDays},"
                + $"sold_amount = {listSold.Count},"
                + $"average_daily = '{averageSales.ToString()}',"
                + $"average_delivery = '{x}"
                + $"WHERE id = {selectedItem.Id};", db))
                {
                    await db.OpenAsync();
                    command2.ExecuteReader();
                }
        }
    }
}

1 个答案:

答案 0 :(得分:2)

您的问题在这里:

tasks.Add(Task.Factory.StartNew(() => ScanProduct(row, desiredDays, deliveryTime, client, db)));

ScanProduct是一个异步函数,因此需要等待。

每次调用Task.Factory.StartNew都会返回一个Task,将使用Task.WaitAll等待它,但是,在每个任务中,调用ScanProduct都将返回 Task,<{>> 不会等待Task.WaitAll

解决方案是将异步lambda与Task.Run结合使用,然后在每种情况下,外部Task都必须先完成ScanProduct才能完成。

tasks.Add(Task.Run(async () => await ScanProduct(row, desiredDays, deliveryTime, client, db)));