繁体   English   中英

为什么等待永远不会回来?

[英]Why does await never return?

我看到等待似乎永远不会回来。 这是示例代码:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private string _status;
    private CancellationTokenSource _cancellationTokenSource;

    public MainWindow()
    {
        InitializeComponent();

        _status = "Ready";

        DataContext = this;
    }

    public string Status
    {
        get { return _status; }
        set
        {
            _status = value;
            OnPropertyChanged(nameof(Status));
        }
    }

    private void OnStart(object sender, RoutedEventArgs e)
    {
        Status = "Running...";

        _cancellationTokenSource = new CancellationTokenSource();

        StartProcessing();
    }

    private void OnStop(object sender, RoutedEventArgs e)
    {
        _cancellationTokenSource.Cancel();
    }

    private async void StartProcessing()
    {
        try
        {
            await new Task(() =>
            {
                Thread.Sleep(5000);
            }, _cancellationTokenSource.Token);
        }
        catch (TaskCanceledException e)
        {
            Debug.WriteLine($"Expected: {e.Message}");
        }

        Status = "Done!";
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

发生的事情是OnStart被调用,它将状态设置为“Running ...”,然后调用StartProcessing。 五秒钟失效,但我从未看到状态设置为“完成!”

如果我调用OnStop,则任务被取消,我看到“完成!” 状态。

我猜我正在创建一个任务以及async / await创建的任务,但它是挂起还是死锁?

这是WPF XAML代码:

<Window x:Class="CancellationSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="Cancellation Test" Height="350" Width="525">
<DockPanel LastChildFill="True">
    <StackPanel DockPanel.Dock="Top">
        <Button Width="70" Margin="5" Click="OnStart">Start</Button>
        <Button Width="70" Margin="5" Click="OnStop">Stop</Button>
    </StackPanel>
    <StatusBar DockPanel.Dock="Bottom">
        <StatusBarItem>
            <TextBlock Text="{Binding Status}"/>
        </StatusBarItem>
    </StatusBar>
    <Grid></Grid>
</DockPanel>
</Window>

您正在创建一个new Task但不启动它,因此它永远不会完成。 而是使用Task.Runawait它。

await Task.Run(() => { });

考虑使用Task.Delay而不是Thread.Sleep这样就不会阻塞当前线程,

您希望避免在方法上使用async void 更新StartProcessing以返回Task ,您还应该使用Task.Delay而不是Thread.Sleep

private async Task StartProcessing() {
    try {
        await Task.Delay(5000, _cancellationTokenSource.Token);
    } catch (TaskCanceledException e) {
        Debug.WriteLine($"Expected: {e.Message}");
    }
    Status = "Done!";
}

接下来,如果OnStart实际上是一个事件处理程序,那么它是允许async void的一个例外。 OnStart更新为异步,然后等待现在等待的StartProcessing

private async void OnStart(object sender, RoutedEventArgs e) {
    Status = "Running...";

    _cancellationTokenSource = new CancellationTokenSource();

    await StartProcessing();
}

最后我建议阅读

Async / Await - 异步编程的最佳实践Stephen Cleary

更好地了解如何使用async / await

暂无
暂无

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

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