C# 多线程 04-使用任务平行库 09-使用 TaskScheduler 配置任务的执行
🏷️ 《C# 多线程》
使用 TaskScheduler 配置任务的执行
本节新建了一个 WPF 项目,用以观察异步时界面的响应效果。
页面代码
xml
<Window x:Class="Recipe4_9.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"
xmlns:local="clr-namespace:Recipe4_9"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBlock
Name="ContentTextBlock"
HorizontalAlignment="Left"
Margin="44,134,0,0"
VerticalAlignment="Top"
Width="425"
Height="40" />
<Button
Content="Sync"
HorizontalAlignment="Left"
Margin="45,190,0,0"
VerticalAlignment="Top"
Width="75"
Click="ButtonSync_Click"/>
<Button
Content="Async"
HorizontalAlignment="Left"
Margin="165,190,0,0"
VerticalAlignment="Top"
Width="75"
Click="ButtonAsync_Click"/>
<Button
Content="Async OK"
HorizontalAlignment="Left"
Margin="285,190,0,0"
VerticalAlignment="Top"
Width="75"
Click="ButtonAsyncOK_Click"/>
</Grid>
</Window>
后台代码
csharp
public MainWindow()
{
InitializeComponent();
}
private void ButtonSync_Click(object sender, RoutedEventArgs e)
{
ContentTextBlock.Text = string.Empty;
try
{
// string result = TaskMethod(TaskScheduler.FromCurrentSynchronizationContext()).Result;
// 同步调用,当前用户界面会被冻结,在任务执行完毕前无法响应任何操作
// TaskMethod 中的 Task 线程无法 UI 线程中的控件 ContentTextBlock,导致发生异常
string result = TaskMethod().Result;
// 该赋值不会被执行到
ContentTextBlock.Text = result;
}
catch (Exception ex)
{
// 出异常时显示异常消息
ContentTextBlock.Text = ex.InnerException.Message;
}
}
private void ButtonAsync_Click(object sender, RoutedEventArgs e)
{
ContentTextBlock.Text = string.Empty;
Mouse.OverrideCursor = Cursors.Wait;
// 异步执行 Task,用户界面不会被冻结,任务执行期间界面仍然可以响应用户操作
// 但是仍然会发生异常
Task<string> task = TaskMethod();
task.ContinueWith(
t =>
{
ContentTextBlock.Text = t.Exception.InnerException.Message;
Mouse.OverrideCursor = null;
},
CancellationToken.None,
TaskContinuationOptions.OnlyOnFaulted,
TaskScheduler.FromCurrentSynchronizationContext());
}
private void ButtonAsyncOK_Click(object sender, RoutedEventArgs e)
{
ContentTextBlock.Text = string.Empty;
Mouse.OverrideCursor = Cursors.Wait;
// 将 UI 线程任务调度程序 (TaskScheduler.FromCurrentSynchronizationContext()) 提供给了任务
Task<string> task = TaskMethod(TaskScheduler.FromCurrentSynchronizationContext());
task.ContinueWith(
t => Mouse.OverrideCursor = null,
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
}
private Task<string> TaskMethod()
{
return TaskMethod(TaskScheduler.Default);
}
private Task<string> TaskMethod(TaskScheduler scheduler)
{
Task delay = Task.Delay(TimeSpan.FromSeconds(5));
return delay.ContinueWith(t =>
{
string str = $"Task is running on a thread id {Thread.CurrentThread.ManagedThreadId}. " +
$"Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
ContentTextBlock.Text = str;
return str;
}, scheduler);
}
执行结果
单击 Sync 按钮:界面无法响应任何操作,异步处理发生异常
单击 Async 按钮:界面可以响应操作,但是异步处理仍然发生异常
单击 Async OK 按钮:界面可以响应操作,异步处理没有发生异常