为什么 await 从不 return?
Why does await never return?
我看到了一个似乎从未出现过的等待 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。五秒钟过去了,但是我从未看到状态设置为 "Done!"
如果我调用 OnStop,任务将被取消,我会看到 "Done!" 状态。
我想我正在创建一个任务以及 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.Run 和 await
。
await Task.Run(() => { });
也考虑使用 Task.Delay 而不是 Thread.Sleep
这样你就不会阻塞当前线程,
您想避免在方法上使用 async void
。将 StartProcessing
更新为 return 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 - Best Practices in Asynchronous Programming By Stephen Cleary
更好地了解如何使用 async/await
我看到了一个似乎从未出现过的等待 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。五秒钟过去了,但是我从未看到状态设置为 "Done!"
如果我调用 OnStop,任务将被取消,我会看到 "Done!" 状态。
我想我正在创建一个任务以及 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.Run 和 await
。
await Task.Run(() => { });
也考虑使用 Task.Delay 而不是 Thread.Sleep
这样你就不会阻塞当前线程,
您想避免在方法上使用 async void
。将 StartProcessing
更新为 return 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 - Best Practices in Asynchronous Programming By Stephen Cleary
更好地了解如何使用 async/await