异步编程模式:从复杂到简洁

在现代软件开发中,异步编程已成为处理并发任务的一种常见方法。它允许程序在等待长时间运行的操作(如数据库访问或网络通信)时继续执行其他任务。然而,异步编程往往伴随着复杂的代码结构和错误处理机制。本文将介绍一种简化异步编程模式的方法,通过使用任务并行库(TPL)和回调函数来提高代码的清晰度和可维护性。

旧模式:复杂且冗长

在旧模式中,通常使用后台工作线程(BackgroundWorker)来处理异步调用。这种方法虽然有效,但代码往往冗长且难以维护。以下是一个典型的后台工作线程代码示例:

void BackgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) { e.Result = _iBLLItemCategory.Select(Convert.ToInt32(e.Argument)); } void BackgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) { if (e.Error == null) { if (e.Result != null) { this.ic_ItemCategory = (ic_ItemCategory)e.Result; } else { _iViewModelUIService.MessageDialog("Data Error", "Record Not Found", string.Format("Item Category key: {0} not found", _objLoadKey.ToString)); } } else { _objIViewModelUIService.ExceptionDialog(e.Error); } }

在这段代码中,可以看到后台工作线程的启动、异常检查、业务层调用、成功结果代码路径和异常结果代码路径。虽然这种模式被广泛接受,但它的复杂性和冗长性促使寻找更好的解决方案。

新模式:简洁且高效

新模式将上述代码简化为一行代码,同时保留了旧模式的所有优点。新模式的关键在于使用回调函数。回调函数允许在异步操作成功或失败时执行特定的操作。以下是一个新模式的示例:

public interface IItemRepository { void GetAll(Action> resultCallback, Action errorCallback); void Get(Int32 itemId, Action resultCallback, Action errorCallback); }

在这个新模式中,定义了一个接口IItemRepository,它包含两个方法:GetAll和Get。这两个方法都接受两个回调函数作为参数:resultCallback和errorCallback。当异步操作成功时,resultCallback被调用;当异步操作失败时,errorCallback被调用。这种模式极大地简化了代码,并提高了可读性和可维护性。

实现新模式:使用任务并行库(TPL

新模式的实现依赖于任务并行库(TPL)。TPL是.NET Framework 4中引入的一个库,它提供了一种简化并行编程的方法。以下是一个使用TPL实现新模式的示例:

[Export(typeof(IItemRepository))] [PartCreationPolicy(CreationPolicy.NonShared)] public class ItemRepository : IItemRepository { readonly ThePhoneCompanyEntities _dataService; [ImportingConstructor] public ItemRepository(DataServiceFacade dataServiceFacade) { _dataService = dataServiceFacade.DataService; } void IItemRepository.GetAll(Action> resultCallback, Action errorCallback) { Task>> task = Task.Factory.StartNew(() => { try { return new RepositoryResult>(_dataService.Items.ToList(), null); } catch (Exception ex) { return new RepositoryResult>(null, ex); } }); task.ContinueWith(r => { if (r.Result.Error != null) { errorCallback(r.Result.Error); } else { resultCallback(r.Result.Package); } }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); } void IItemRepository.Get(Int32 itemId, Action resultCallback, Action errorCallback) { if (itemId != 0) { Task> task = Task.Factory.StartNew(() => { try { return new RepositoryResult(_dataService.Items.Where(i => i.ItemID == itemId).FirstOrDefault(), null); } catch (Exception ex) { return new RepositoryResult(null, ex); } }); task.ContinueWith(r => { if (r.Result.Error != null) { errorCallback(r.Result.Error); } else { resultCallback(r.Result.Package); } }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); } else { resultCallback(((IItemRepository)this).Create()); } } Item IItemRepository.Create() { return new Item(); } }

在这个实现中,使用了TPL的Futures模式。这种模式允许在后台线程中执行异步操作,并在操作完成后在调用线程上调用回调函数。这种实现方式不仅简化了代码,还提高了性能。

1. 实际执行工作的代码被包装在try-catch块中,以处理可能发生的异常。 2. 异步操作的结果被包装在一个RepositoryResult对象中。 3. RepositoryResult用于在调用线程上调用resultCallback或errorCallback。 4. TaskScheduler.FromCurrentSynchronizationContext方法调用确保两个回调在调用线程上被调用。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485