多線程之異步編程: 經典和最新的異步編程模型, IAsyncInfo 與 Task 相互轉換
介紹
重新想象 Windows 8 Store Apps 之 異步編程
經典的異步編程模型(IAsyncResult)
最新的異步編程模型(async 和 await)
將 IAsyncInfo 轉換成 Task
將 Task 轉換成 IAsyncInfo
示例
1、使用經典的異步編程模型(IAsyncResult)實現一個支持異步操作的類
Thread/Async/ClassicAsync.cs
/*
* 使用經典的異步編程模型(IAsyncResult)實現一個支持異步操作的類
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace XamlDemo.Thread.Async
{
public class ClassicAsync
{
private delegate string HelloDelegate(string name);
private HelloDelegate _helloDelegate;
public ClassicAsync()
{
_helloDelegate = new HelloDelegate(Hello);
}
private string Hello(string name)
{
new ManualResetEvent(false).WaitOne(3000);
return "hello: " + name;
}
// begin 方法
public IAsyncResult BeginRun(string name, AsyncCallback callback, Object state)
{
// 新開線程,去執行 Hello() 方法,callback 是回調,state 是上下文
return _helloDelegate.BeginInvoke(name, callback, state);
}
// end 方法
public string EndRun(IAsyncResult ar)
{
if (ar == null)
throw new NullReferenceException("IAsyncResult 不能為 null");
return _helloDelegate.EndInvoke(ar);
}
}
}
Thread/Async/ClassicAsyncDemo.xaml
<Page
x:Class="XamlDemo.Thread.Async.ClassicAsyncDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Thread.Async"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="Transparent">
<StackPanel Margin="120 0 0 0">
<TextBlock Name="lblMsg" FontSize="14.667" />
<Button Name="btnIAsyncResult" Content="IAsyncResult 的 Demo" Click="btnIAsyncResult_Click_1" Margin="0 10 0 0" />
</StackPanel>
</Grid>
</Page>
Thread/Async/ClassicAsyncDemo.xaml.cs
/*
* 演示如何通過經典的異步編程模型(IAsyncResult)來進行異步操作
*
* IAsyncResult - 異步操作結果
* AsyncState - 上下文
* IsCompleted - 異步操作是否已完成
* AsyncWaitHandle - 獲取用於等待異步操作完成的 System.Threading.WaitHandle 對象(通過WaitHandle.WaitOne() 在當前線程等待)
*/
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace XamlDemo.Thread.Async
{
public sealed partial class ClassicAsyncDemo : Page
{
System.Threading.SynchronizationContext _syncContext;
public ClassicAsyncDemo()
{
this.InitializeComponent();
// 獲取當前 UI 線程
_syncContext = System.Threading.SynchronizationContext.Current;
}
private void btnIAsyncResult_Click_1(object sender, RoutedEventArgs e)
{
ClassicAsync classicAsync = new ClassicAsync();
IAsyncResult ar = classicAsync.BeginRun("webabcd", new AsyncCallback(Callback), classicAsync);
lblMsg.Text = "開始執行,3 秒後完成";
}
private void Callback(IAsyncResult ar)
{
ClassicAsync classicAsync = (ClassicAsync)ar.AsyncState;
string result = classicAsync.EndRun(ar);
_syncContext.Post(
(ctx) =>
{
lblMsg.Text = result;
},
null);
}
}
}
2、演示如何通過最新的異步編程模型(async 和 await)來進行異步操作
Thread/Async/NewAsyncDemo.xaml
<Page
x:Class="XamlDemo.Thread.Async.NewAsyncDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Thread.Async"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="Transparent">
<StackPanel Margin="120 0 0 0">
<TextBlock Name="lblMsg" FontSize="14.667" />
<Button Name="btnTaskWithoutReturn" Content="執行一個不帶返回值的 Task" Click="btnTaskWithoutReturn_Click_1" Margin="0 10 0 0" />
<Button Name="btnTaskWithReturn" Content="執行一個帶返回值的 Task" Click="btnTaskWithReturn_Click_1" Margin="0 10 0 0" />
<Button Name="btnMultiTask" Content="並行執行多個 Task" Click="btnMultiTask_Click_1" Margin="0 10 0 0" />
<Button Name="btnTaskWithoutAwait" Content="執行一個不 await 的 Task" Click="btnTaskWithoutAwait_Click_1" Margin="0 10 0 0" />
</StackPanel>
</Grid>
</Page>
Thread/Async/NewAsyncDemo.xaml.cs
/*
* 演示如何通過最新的異步編程模型(async 和 await)來進行異步操作
*
* 注:
* 1、要想 await,其所在方法必須標記為 async
* 2、方法被標記為 async 是為了讓編譯器重新編寫該方法,使 await 中的內容重新編寫為具有GetAwaiter() 等實際異步邏輯的代碼
*/
using System;
using System.Threading;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace XamlDemo.Thread.Async
{
public sealed partial class NewAsyncDemo : Page
{
private static int _count = 0;
public NewAsyncDemo()
{
this.InitializeComponent();
}
// 不帶返回值的 Task
private async Task TaskWithoutReturn()
{
// 在另一個線程 sleep 1000 毫秒,然後回到 UI 線程
await Task.Delay(1000);
// await Task.Delay(Timeout.Infinite); 長眠於此
// await Task.Delay(Timeout.InfiniteTimeSpan); 長眠於此
// 直接在當前線程 sleep 可以使用如下方法,因為 WinRT 中沒有 Thread.Sleep() 了
// new ManualResetEvent(false).WaitOne(1000);
Interlocked.Increment(ref _count);
}
// 帶返回值的 Task
private async Task<int> TaskWithReturn()
{
await Task.Delay(1000);
Interlocked.Increment(ref _count);
return _count;
}
// 演示不帶返回值的異步操作
private async void btnTaskWithoutReturn_Click_1(object sender, RoutedEventArgs e)
{
// ConfigureAwait(false) - 異步操作後不返回 UI 線程,可節省一點點資源。默認值:ConfigureAwait(true)
await TaskWithoutReturn().ConfigureAwait(false);
lblMsg.Text = "count: " + _count.ToString();
}
// 演示帶返回值的異步操作
private async void btnTaskWithReturn_Click_1(object sender, RoutedEventArgs e)
{
int result = await TaskWithReturn();
lblMsg.Text = "count: " + result.ToString();
}
// 演示多任務並行執行的異步操作
private async void btnMultiTask_Click_1(object sender, RoutedEventArgs e)
{
Task task = Task.WhenAll(TaskWithoutReturn(), TaskWithoutReturn(), TaskWithoutReturn());
DateTime dt = DateTime.Now;
await task;
lblMsg.Text = "count: " + _count.ToString() + ", 執行
Thread/Async/IAsyncInfo2Task.xaml.cs
/*
* 演示如何將 IAsyncInfo(IAsyncAction, IAsyncOperation, IAsyncActionWithProgress, IAsyncOperationWithProgress) 轉成 Task
*/
using System;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace XamlDemo.Thread.Async
{
public sealed partial class IAsyncInfo2Task : Page
{
public IAsyncInfo2Task()
{
this.InitializeComponent();
}
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
// 用於取消 Task
CancellationTokenSource cts = new CancellationTokenSource();
// 創建一個 IAsyncInfo
IAsyncOperation<int> action = AsyncInfo.Run<int>(
(token) =>
Task.Run<int>(
() =>
{
token.WaitHandle.WaitOne(3000);
token.ThrowIfCancellationRequested();
return 10 * 10;
},
token));
lblMsg.Text = "開始執行,3 秒後完成";
// 將 IAsyncOperation 轉換成 Task
// AsTask() 是擴展方法,其邏輯在 System.WindowsRuntimeSystemExtensions 類中
Task<int> task = action.AsTask<int>(cts.Token);
int result = await task;
lblMsg.Text = "結果:" + result.ToString();
}
}
}
4、演示如何將 Task 轉成 IAsyncInfo(IAsyncAction, IAsyncOperation)
Thread/Async/Task2IAsyncInfo.xaml
<Page
x:Class="XamlDemo.Thread.Async.Task2IAsyncInfo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Thread.Async"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="Transparent">
<StackPanel Margin="120 0 0 0">
<TextBlock Name="lblMsg" FontSize="14.667" />
</StackPanel>
</Grid>
</Page>
Thread/Async/Task2IAsyncInfo.xaml.cs
/*
* 演示如何將 Task 轉成 IAsyncInfo(IAsyncAction, IAsyncOperation)
*/
using System;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace XamlDemo.Thread.Async
{
public sealed partial class Task2IAsyncInfo : Page
{
public Task2IAsyncInfo()
{
this.InitializeComponent();
}
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
// 用於取消 IAsyncInfo(注意:本例中的 IAsyncInfo 是從 Task 轉換過來的,所以IAsyncInfo.Cancel() 方法無效)
CancellationTokenSource cts = new CancellationTokenSource();
// 創建一個 Task
Task<int> task = Task.Run<int>(
() =>
{
cts.Token.WaitHandle.WaitOne(3000);
cts.Token.ThrowIfCancellationRequested();
return 10 * 10;
},
cts.Token);
lblMsg.Text = "開始執行,3 秒後完成";
// 將 Task 轉換成 IAsyncOperation
// AsAsyncAction(), AsAsyncOperation() 是擴展方法,其邏輯在System.WindowsRuntimeSystemExtensions 類中
IAsyncOperation<int> operation = task.AsAsyncOperation<int>();
int result = await operation;
lblMsg.Text = "結果:" + result.ToString();
}
}
}
OK
[源碼下載]:http://files.cnblogs.com/webabcd/Windows8.rar