简体   繁体   English

是否可以保证对同一任务恢复多个等待表达式的顺序?

[英]Is the order of resume multiple await expressions to the same task is guaranteed?

I'm learning about async/await with C# 4.5 and wondering what happens when multiple "awaiters" are awaiting the same task. 我正在学习使用C#4.5进行异步/等待,并想知道当多个“等待者”正在等待同一任务时会发生什么。

I'm doing some experimentation and I think that I understand what's happening. 我正在做一些实验,我想我了解发生了什么。 However, i have some questions to ask: 但是,我有一些问题要问:

Look at this piece of code: 看一下这段代码:

AsyncAwaitExperiment.fxml.cs 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 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>

The behavior of this code is: 此代码的行为是:

  1. Start an async long running operation when the button "start" is pressed. 当按下“开始”按钮时,开始异步长时间运行操作。
  2. Stop the async operation when the button "stop" is pressed. 当按下“停止”按钮时,停止异步操作。
  3. When the "first Await" button is pressed, await for the task to finish and then print something on the console. 当按下“第一个等待”按钮时,等待任务完成,然后在控制台上打印一些内容。
  4. The same with the second button ("second await"). 与第二个按钮相同(“第二个等待”)。

With this piece of code and some break points I have noticed some behaviors. 通过这段代码和一些断点,我注意到了一些行为。

  1. When i await a task it will resume the code at the point that it was stopped previously. 当我等待任务时,它将在先前已停止的位置恢复代码。 Nothing new here, i guess. 我猜这里没什么新鲜的。
  2. If (this is the interesting part) I have more than one "awaiter" for the same task, it will resume in same order of the code that awaited. 如果(这是有趣的部分)我为同一任务有多个“等待者”,则它将按等待的代码的相同顺序恢复。 EX: if the firstAwait was clicked first and the secondAwait second, when the task finishes and the resume of the code flow will follow the same order: first await and then second await. 例如:如果首先单击了firstAwait,然后单击了secondAwait,则当任务完成时,代码流的恢复将遵循相同的顺序:先等待,然后再等待。

The questions are: 问题是:

  1. Is there any guarantee of this behavior (about the order of the resume) ? 是否可以保证这种行为(关于简历的顺序)?
  2. Is there any problem in using this scheduler (TaskScheduler.Current) ? 使用此调度程序(TaskScheduler.Current)是否有任何问题?
  3. Can I re-use the cancellation token or do I really need to create one every time that I cancel and start a task ? 我可以重用取消令牌吗?或者每次取消并启动任务时我真的需要创建一个吗?

PS: Sorry for my bad english :/ PS:对不起,我的英语不好:/

You shouldn't assume anything about the order in which activities will resume. 您不应对活动的恢复顺序承担任何责任。 Supposing that, in the future, someone managed to write a new UI system that was entirely multi-threaded, you'd expect even UI threads to run in parallel (Notes: No-one thinks it's sane to write a multi-threaded UI system currently; Even if two tasks resume "at the same time", one of them could be indefinitely paused) 假设将来有人设法编写一个完全是多线程的新UI系统,那么您甚至期望UI线程可以并行运行(注意:没有人认为编写多线程UI系统是理智的。当前;即使“同时”恢复执行两个任务,也可能会无限期地暂停其中一项)

If there are dependencies between activities in your code, make them explicit. 如果活动之间的依赖关系在你的代码,使他们明确。 Otherwise, assume that they may occur in any order and may be interleaved. 否则,假设它们可能以任何顺序发生并且可能被交错。 That's the only sane way to program. 那是编程的唯一明智的方法。

And, finally, no. 最后,没有。 Once you've used a CancellationToken , it's done. 使用CancellationToken ,就完成了。 If you need another one, you need to create a new one. 如果需要另一个,则需要创建一个新的。 This actually makes thinking about multiple tasks/activities simpler to think about - no token can go from being cancelled to being uncancelled. 实际上,这使考虑多个任务/活动变得更容易考虑-从取消令牌到取消令牌都不可能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM