永远不会从 Task.WaitAll 回来

Never coming back from Task.WaitAll

仍在加快 Xamarin 和 C# 的速度。

我有一些代码:

        List<Task<int>> taskList = new List<Task<int>>();
        ConfigEntry siteId = new ConfigEntry
        {
            ConfigKey = KEY_SITE_ID,
            ConfigValue = siteInfo.siteId
        };
        taskList.Add(ConfigDatabase.SaveConfigAsync(siteId));

        ConfigEntry productId = new ConfigEntry
        {
            ConfigKey = KEY_PRODUCT_ID1,
            ConfigValue = siteInfo.products[0].productId.ToString()
        };
        taskList.Add(ConfigDatabase.SaveConfigAsync(productId));

总共有 9 个被添加到 taskList。这些中的每一个都将内容插入到 SQLITE 中。这是代码 运行:

    public async Task<int> SaveConfigAsync(ConfigEntry entry)
    {
        if (entry.ConfigKey == null)
        {
            throw new Square1Exception("Config entry key not defined:" + entry);
        }
        else
        {
            try
            {
                ConfigEntry existing = await GetConfigAsync(entry.ConfigKey);
                if (existing == null)
                {
                    return await _database.InsertAsync(entry);
                }
                else
                {
                    existing.UpdateFrom(entry);
                    return await _database.UpdateAsync(entry);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error while saving value:" + entry.ConfigKey);
                throw ex;
            }
        }
    }

因此,在构建此任务列表的最后,我有以下行:

        Task.WaitAll(taskList.ToArray());

我曾希望等到所有添加完成后再退出。相反,它永远不会从这里回来。它只是挂起我的整个应用程序。也没有在日志中看到任何内容。它(可能)在创建时启动任务还是等到 WaitAll 之类的东西?

如果我用 await 和单线程替换每个添加,它们就可以正常工作。可能阻塞在数据库或磁盘上?

想法?

You shouldn't block on asynchronous code.

最好的解决方法是将 Task.WaitAll(taskList.ToArray()); 更改为 await Task.WhenAll(taskList);

如果您必须阻塞,那么您可以使用Task.Run将工作推送到后台线程,例如:

taskList.Add(Task.Run(() => ConfigDatabase.SaveConfigAsync(siteId)));
...
taskList.Add(Task.Run(() => ConfigDatabase.SaveConfigAsync(productId)));

但是那样的话您会在 Task.WaitAll 阻塞您的 UI 线程,所以我不推荐这种方法。使用 await Task.WhenAll 更好。

您在执行 Task.WhenAll(任务)时缺少 await。 尝试以下解决方案:

ConfigEntry siteId = new ConfigEntry
{
    ConfigKey = KEY_SITE_ID,
    ConfigValue = siteInfo.siteId
};
ConfigEntry productId = new ConfigEntry
{
    ConfigKey = KEY_PRODUCT_ID1,
    ConfigValue = siteInfo.products[0].productId.ToString()
};

var insertResultFirstTask = ConfigDatabase.SaveConfigAsync(siteId)
var insertResultSecondTask = ConfigDatabase.SaveConfigAsync(productId)

IEnumerable<Task> tasks = new List<Task>() {
    insertResultFirstTask,
    insertResultSecondTask
};

await Task.WhenAll(tasks);

var insertResultFirst = insertResultFirstTask.Result;
var insertResultSecond = insertResultSecondTask.Result;