【问题标题】:Is the order of resume multiple await expressions to the same task is guaranteed?是否保证了对同一任务恢复多个等待表达式的顺序?
【发布时间】:2015-12-15 17:52:50
【问题描述】:

我正在使用 C# 4.5 学习异步/等待,并想知道当多个“等待者”等待同一任务时会发生什么。

我正在做一些实验,我认为我了解正在发生的事情。但是,我有一些问题要问:

看这段代码:

AsyncAwaitExperiment.fxml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace View
{
    /// <summary>
    /// Interaction logic for AsyncAwaitExperiment.xaml
    /// </summary>
    public partial class AsyncAwaitExperiment : Window
    {

        private CancellationTokenSource token;
        private Task longRunningTask;

        public AsyncAwaitExperiment()
        {
            InitializeComponent();
        }

        private void startAsyncOperation(object sender, RoutedEventArgs e)
        {
            if (longRunningTask != null && !longRunningTask.IsCompleted)
            {
                return;
            }
            else
            {
                longRunningTask = null;
                token = new CancellationTokenSource();
            }

            Action action = () => 
            {
                while (!token.Token.IsCancellationRequested)
                {
                    Thread.Sleep(100);
                }
            };

            longRunningTask = Task.Factory.StartNew(
                action,
                token.Token, 
                TaskCreationOptions.LongRunning,
                TaskScheduler.Current);
        }

        private void stopOperation(object sender, RoutedEventArgs e)
        {
            if (longRunningTask == null
                || longRunningTask.IsCompleted
                || token == null
                || token.Token.IsCancellationRequested)
            {
                return;
            }
            token.Cancel();
        }

        private async void firstAwait(object sender, RoutedEventArgs e)
        {
            if (longRunningTask == null || longRunningTask.IsCompleted)
                return;
            await longRunningTask;
            Console.WriteLine("First Method");
        }

        private async void secondAwait(object sender, RoutedEventArgs e)
        {
            if (longRunningTask == null || longRunningTask.IsCompleted)
                return;
            await longRunningTask;
            Console.WriteLine("Second Method");
        }
    }
}

AsyncAwaitExperiment.fxml

<Window x:Class="View.AsyncAwaitExperiment"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="AsyncAwaitExperiment" Height="300" Width="300">
    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Content="Start Async" Margin="3" Click="startAsyncOperation" />
            <Button Content="Stop Async" Margin="3" Click="stopOperation" />
            <Button Content="Await First" Margin="3" Click="firstAwait" />
            <Button Content="Await Second" Margin="3" Click="secondAwait" />
        </StackPanel>
    </Grid>
</Window>

这段代码的行为是:

  1. 按钮时启动异步长时间运行操作 按下“开始”。
  2. 当按钮“停止”时停止异步操作 按下。
  3. 当按下“第一个等待”按钮时,等待任务 完成,然后在控制台上打印一些东西。
  4. 与第二个按钮相同(“第二个等待”)。

通过这段代码和一些断点,我注意到了一些行为。

  1. 当我等待一个任务时,它会从原来的位置恢复代码 之前停过。我猜这里没有什么新鲜事。
  2. 如果(这是有趣的部分)我有多个“等待者” 同样的任务,它将按照等待的代码顺序恢复。 EX:如果先点击了 firstAwait,然后点击了 secondAwait, 当任务完成并且代码流的恢复将遵循 相同的顺序:先等待,然后再等待。

问题是:

  1. 这种行为是否有任何保证(关于 简历)?
  2. 使用这个调度器(TaskScheduler.Current)有什么问题吗 ?
  3. 我可以重复使用取消令牌还是真的需要创建一个 每次我取消并开始一项任务?

PS:抱歉我的英语不好:/

【问题讨论】:

  • 我不认为它是有保证的,我不想假设它是这样,然后得到损坏的代码。如果代码片段之间存在其他依赖关系(例如您确实需要特定的顺序),为什么不明确说明呢?
  • 多个等待者不是一个典型的场景——在这种人为的情况下,我不会对可能发生或可能不会发生的事情做出任何假设。此外,您使用的是async void,这使得异步方法本质上是触发并忘记。您的应用程序可以在这些方法完成之前终止。在任何情况下,从await 恢复可以发生在任何线程、任何内核上。
  • @Damien_The_Unbeliever 在这种情况下不需要特定的顺序。我怀疑的是行为,只是它。
  • 主要问题是我没有找到任何关于排序的信息,编译器也没有警告过这样的事情。
  • 那么,如果我们说“什么都不做”,那么您的进展如何?那肯定是起点。这个问题看起来你正在寻求特定的保证

标签: c# .net asynchronous async-await


【解决方案1】:

您不应该对恢复活动的顺序做出任何事情。假设将来有人设法编写了一个完全多线程的新 UI 系统,您会期望 UI 线程也可以并行运行(注:没有人认为编写多线程 UI 系统是正常的目前;即使两个任务“同时”恢复,其中一个任务可能会无限期暂停)

如果代码中的活动之间存在 依赖关系,请将它们明确化。否则,假设它们可能以任何顺序出现并且可能是交错的。这是唯一明智的编程方式。

最后,没有。一旦你使用了CancellationToken,它就完成了。如果您需要另一个,则需要创建一个新的。这实际上使得考虑多个任务/活动更容易考虑 - 没有令牌可以从被取消到被取消。

【讨论】:

  • “其中一个可能被无限期暂停”,等待暂停线程?
  • 那“TaskScheduler.Current”呢,这样用就好了?
猜你喜欢
  • 2016-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-17
  • 1970-01-01
  • 2015-05-22
  • 2021-12-27
  • 1970-01-01
相关资源
最近更新 更多