.NET开发者的异步编程指南

随着移动设备的普及,异步编程成为了开发者必须掌握的技能之一。幸运的是,如果是一名.NET开发者,可以利用现有的技能和语言,针对一些最受欢迎的移动操作系统进行开发。Windows Phone7是由微软开发的移动操作系统,它是Windows Mobile平台的继任者。

异步编程模型

.NET框架提供了多种异步编程模型,可以使用以下任一模型来向客户端代码公开异步特性:

IAsyncResult自.NET1.0以来就已经存在,并在大多数BCL类中使用。EAP的主要优点是它与Visual Studio UI设计器集成。可以通过MSDN上的优秀文章学习如何正确实现IAsyncResult接口(APM):,作者Jeffrey Richter。

使用IAsyncResult接口

在本文中,将展示如何在Windows Phone7上使用实现IAsyncResult接口的类型是多么容易。将使用PowerThreading库,因为它提供了类似于(甚至可以说是改进了)原始MSDN文章中描述的实现。将解释如何使用它以及如何使用AsyncEnumerator类使其变得更容易。

上述代码用于演示。这段代码进行了I/O操作,导致线程阻塞。

public interface IWebService { IStockQuote FetchStockQuotes(); } internal sealed class WebService : IWebService { private readonly IStockQuote m_quotes; public WebService(IStockQuote quotes) { m_quotes = quotes; } public IStockQuote FetchStockQuotes() { Thread.Sleep(50); // 模拟耗时任务 return m_quotes; } }

下面的代码展示了ExecuteWithSyncIO方法的实现。应用程序向用户显示一个消息框,表明UI将在执行过程中暂停。

private void ExecuteWithSyncIO() { for (Int32 n = 0; n < c_iterations; n++) { m_webService.GetStockQuotes(); } SetStatus("Sync/IO completed.", StatusState.Ready); }

下面的代码展示了ExecuteWithDelegateBeginInvoke方法的实现。这个方法只是为了演示,因为在Compact Framework中不允许异步调用委托。

private void ExecuteWithDelegateBeginInvoke() { Func stockQuoteDelegate = m_webService.GetStockQuotes; stockQuoteDelegate.BeginInvoke((ar) => { stockQuoteDelegate.EndInvoke(ar); }, null); }

解决方案

Wintellect.Threading.AsyncProgModel.AsyncResult<TResult>类包含了IAsyncResult接口的实现。这个类型是泛型的,可以轻松地在WebService类上使用它。

using System; using System.Threading; using Wintellect.Threading.AsyncProgModel; public interface IWebService { IStockQuote FetchStockQuotes(); } internal sealed class WebService : IWebService { private readonly IStockQuote m_quotes; public WebService(IStockQuote quotes) { m_quotes = quotes; } public IAsyncResult BeginGetStockQuotes(AsyncCallback callback, Object state) { AsyncResult ar = new AsyncResult(callback, state); ThreadPool.QueueUserWorkItem(GetStockQuotesHelper, ar); return ar; } public IStockQuote EndGetStockQuotes(IAsyncResult asyncResult) { AsyncResult ar = (AsyncResult)asyncResult; return ar.EndInvoke(); } private void GetStockQuotesHelper(Object state) { AsyncResult ar = (AsyncResult)state; try { IStockQuote quotes = FetchStockQuotes(); ar.SetAsCompleted(quotes, false); } catch (Exception e) { ar.SetAsCompleted(e, false); } } public IStockQuote FetchStockQuotes() { Thread.Sleep(5); // 模拟耗时任务 return m_quotes; } }

IAsyncResult接口

下面的代码展示了ExecuteWithIAsyncResult方法的实现。唯一的问题是,使用IAsyncResult时,需要指定一个方法,以便在相应的异步操作完成时调用。这可能导致使用同步构造来避免竞态条件。它还会分割代码流。可以使用匿名方法或Lambda表达式内联回调方法,如下所示,但如果逻辑很复杂,代码就不会很漂亮。

private void ExecuteWithIAsyncResult() { SetStatus("Working..", StatusState.Busy); for (Int32 n = 0; n < c_iterations; n++) { m_webService.BeginGetStockQuotes((ar) => { if (Interlocked.Increment(ref m_numDone) == c_iterations) { Execute.OnUIThread(() => { SetStatus("IAsyncResult APM completed.", StatusState.Ready); }); } }, null); } }

AsyncEnumerator类

下面的代码展示了ExecuteWithAsyncEnumerator方法的实现。正如看到的,这个方法使代码看起来像是同步执行的,但实际上它是异步执行的。不需要将代码分割成回调方法或内联委托。不需要使用Dispatcher或SynchronizationContext在UI线程中进行调用。所有这些工作都由AsyncEnumerator类处理。

private IEnumerator ExecuteWithAsyncEnumerator(AsyncEnumerator ae) { for (Int32 n = 0; n < c_iterations; n++) { m_webService.BeginGetStockQuotes(ae.End(), null); } ae.SyncContext = null; yield return c_iterations; for (Int32 n = 0; n < c_iterations; n++) { m_webService.EndGetStockQuotes(ae.DequeueAsyncResult()); } SetStatus("AsyncEnumerator completed.", StatusState.Ready); }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485