【问题标题】:Continuation tasks not executing in correct order未按正确顺序执行的继续任务
【发布时间】:2013-06-18 01:24:14
【问题描述】:

一直在尝试按顺序执行任务,但它们是按随机顺序执行的。

  • 在 .ContinueWith 之后附加 .Unwrap 没有帮助
  • 从这些方法而不是 Task 返回 T 的 Task 并将其结果分配给调用者也不起作用

不确定我的方法的签名,它们是否应该包含 async/await。

排序任务:

Task biographies = LoadArtistBiographies(apiKey);
Task blogs = LoadArtistBlogs(apiKey);
Task familiarity = LoadArtistFamiliarity(apiKey);
Task hottness = LoadArtistHottness(apiKey);
Task images = LoadArtistImages(apiKey);

await biographies.ContinueWith(b => blogs);
await blogs.ContinueWith(f => familiarity);
await familiarity.ContinueWith(h => hottness);
await hottness.ContinueWith(i => images);
await images;

执行方法示例:

private async Task LoadArtistBiographies(string apiKey)
{
    var parameters = new ArtistBiographiesParameters();
    parameters.SetDefaultValues();
    parameters.ApiKey = apiKey;
    parameters.Id = _artistId;
    ArtistBiographies biographies = await Queries.ArtistBiographies(parameters);
    ItemsControlBiographies.ItemsSource = biographies.Biographies;
}

Queries.* 方法也是异步的:

public static async Task<ArtistBlogs> ArtistBlogs(ArtistBlogsParameters parameters)

链接那些本身正在执行异步任务的任务的正确语法是什么?

【问题讨论】:

  • 好的,谢谢大家的回答!积分分配时间:)

标签: c# async-await


【解决方案1】:

如果你想按特定顺序执行任务,你应该直接await他们:

await LoadArtistBiographies(apiKey);
await LoadArtistBlogs(apiKey);
await LoadArtistFamiliarity(apiKey);
await LoadArtistHottness(apiKey);
await LoadArtistImages(apiKey);

这将导致第二个任务 (LoadArtistBlogs) 在第一个任务完成后安排。

现在,任务正在“以随机顺序”执行,因为您已将它们分配给 Task 实例,这允许每个实例同时执行。

话虽如此,我实际上建议更改您的方法以返回值,而不是在方法中将它们分配给数据源:

private async Task<Biographies> LoadArtistBiographiesAsync(string apiKey)
{
    var parameters = new ArtistBiographiesParameters();
    parameters.SetDefaultValues();
    parameters.ApiKey = apiKey;
    parameters.Id = _artistId;
    var bio = await Queries.ArtistBiographies(parameters);
    return bio.Biographies;
}

你可以这样写:

ItemsControlBiographies.ItemsSource = await LoadArtistBiographiesAsync(apiKey);
// Other methods below, with await as this example

在我看来,这使得逻辑流经异步方法时的意图更加清晰。

【讨论】:

  • 我建议的一项更改是启动所有任务,以便它们同时运行,然后在所有任务启动后等待结果,这样你就不需要等待LoadArtistBiographies在您开始寻找 LoadArtistBlogs 之前返回(如果您正在使用的 API 允许同时调用多个,如果您一次只允许一个调用,那么 Reed 的方式将是正确的方法)。
  • @ScottChamberlain 问题的整个前提是他正在按照您的描述进行操作,并在等待所有这些操作之前并行执行它们这不是他想要的.
  • @ScottChamberlain OP 有那个原件,但明确表示他希望 事情按顺序运行(不知道为什么)。我确实同意,一般来说,我会开始任务,然后按顺序等待。来自帖子:“一直在尝试按顺序执行任务”
  • @Servy 这就是为什么我将其添加为评论而不是答案的原因,如果他决定从异步任务序列进行更改,那更像是“嘿,请注意这一点”到一组并行任务,所以他不需要回来回答关于“如何同时启动多个异步任务”的第二个问题。我经常看到人们认为您必须await 放在调用 async 函数的同一行。
  • 当同时执行它们时,UI似乎冻结,直到几秒钟后什么都没有发生。按顺序执行它们看起来更优雅,因为它们一个一个地发生,并且用户体验不那么无聊,因为在等待图像时有一些东西可以看,这是迄今为止等待时间最长的。
【解决方案2】:

您的示例代码将开始执行所有任务,而无需等待每个任务完成。然后它等待他们按顺序完成

关键是async 方法会在您调用它时启动。因此,如果您还不想启动它,请不要调用该方法:

await LoadArtistBiographies(apiKey);
await LoadArtistBlogs(apiKey);
await LoadArtistFamiliarity(apiKey);
await LoadArtistHottness(apiKey);
await LoadArtistImages(apiKey);

【讨论】:

  • 我想在每种情况下也可以使用var task = Task.Run(()=&gt;LoadArtist(apikey)); await task
  • @Gerard:如果你想卸载到后台线程,你应该只使用Task.Run。如果你有一个自然异步操作(比如从服务器加载艺术家),那么你应该使用异步实现而不是Task.Run
  • 恐怕我不明白区别:'卸载到后台线程'和'异步实现'。刚刚问了一个相关的问题(等待的任务没有优雅地处理异常)。
  • @Gerard:异步实现在操作进行时不会阻塞线程。我有一个blog post 描述async 调用如何避免阻塞线程。
  • 我喜欢您开始博客的方式:“这是最纯粹形式的异步的基本真理:没有线程。”
【解决方案3】:

await 将等待给定任务完成,它不会启动任务。您的 Load* 方法最有可能启动一项任务。所有五个任务都以任意顺序运行。

当您到达await 时,您的任务可能已经完成,也可能尚未完成。不要紧。你在它上面调用ContinueWith,告诉你的任务一旦完成它应该继续使用这个方法。这将返回一个新的任务,你终于等待了。

【讨论】:

    【解决方案4】:

    实际上我刚刚找到了一种方法,但没有 ContinueWith :

    ArtistBiographies biographies = await LoadArtistBiographies(apiKey);
    ItemsControlBiographies.ItemsSource = biographies.Biographies;
    
    ArtistBlogs blogs = await LoadArtistBlogs(apiKey);
    ItemsControlBlogs.ItemsSource = blogs.Blogs;
    
    ArtistFamiliarity familiarity = await LoadArtistFamiliarity(apiKey);
    ContentControlFamiliarity.Content = familiarity.artist;
    
    ArtistHotttnesss hottness = await LoadArtistHottness(apiKey);
    ContentControlHottness.Content = hottness.Artist;
    
    ArtistImages images = await LoadArtistImages(apiKey);
    ItemsControlImages.ItemsSource = images.Images;
    

    很好奇是否有人可以使用 ContinueWith 提供答案。

    【讨论】:

    • 重点是您不需要 ContinueWith。通常,无论如何你都应该使用await 而不是ContinueWith
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-13
    • 2013-11-10
    • 2019-07-01
    • 2023-01-17
    相关资源
    最近更新 更多