您好,欢迎来到时间财富网
全部需求分类
当前位置:首页 > 移动应用 > .NET Framework 精简版后台处理技术
.NET Framework 精简版后台处理技术
2015/8/14 15:34:26   作者:心缘新   人气:1174次  评论(0)
所属标签: 移动应用开发 
  摘要:执行后台处理牵涉到很多方面,要求非常仔细地进行设计。本文提供了一些有关充分利用后台处理的建议,并提出了很多必须解决的问题。 

 

  应用程序通常需要在后台执行长时间运行的操作,同时还要提供积极的、响应及时的用户体验。这种情况在智能设备开发过程中最为常见。Pocket PC 上运行的应用程序必须能够随时执行用户所需的任务,但是,由于此类设备的 CPU 处理能力通常都有限,而且常常使用低带宽连接,因此限制了很多进程的执行速度,对较为复杂的应用程序更是如此。通常情况下,要处理长时间运行的任务,最好是在后台进行长时间处理,同时使用户可以与应用程序进行交互。 



  执行后台处理牵涉到很多方面,要求非常仔细地进行设计。下面提供了一些有关充分利用后台处理的建议,并提出了很多必须解决的问题。



  后台处理的类型

  .net Framework 精简版提供了三种基本技术,支持将长时间运行的处理移到后台进行。异步 XML Web Service、线程池和显式创建的线程这三种技术分别适用于不同的情况,需要正确地应用和管理。 



  异步 XML Web Service

  Web 服务为智能设备与中央服务之间的通信提供了一种易于使用的机制。通常情况下,Web 服务必须传输大量数据,而且必须通过低速移动连接来实现传输。此类长时间运行的数据传输最适合利用 .NET Framework 精简版的功能来异步管理 Web 服务调用。

  通常情况下,Web 服务是通过 Visual Studio .NET 的“Add Web Reference”(添加 Web 引用)或 WSDL 命令行实用程序生成的代理类调用的。利用此技术,应用程序开发人员可以对代理类调用本地方法,控制实际调用远程 Web 服务所需的 XML 的生成、传输和分析等方面的细节。生成的代理类为每个 Web 服务操作提供三个方法。其中一个方法的名称与异步调用 Web 服务的 Web 服务操作相同,另外两个方法的前缀分别为“Begin”和“End”,用于异步调用 Web 服务。例如,执行 Add(添加)操作的 Web 服务代理包含名为 Add、BeginAdd 和 EndAdd 的方法。



  注意:有关使用 Visual Studio .NET 的“Add Web Reference”(添加 Web 引用)功能的详细信息,请参阅 Adding and Removing Web References(英文)。有关 WSDL 命令行实用程序的详细信息,请参阅 Web Services Description Language Tool(英文)。



  进行异步 Web 服务调用

  异步启动 Web 服务与调用该操作的“Begin”方法一样简单。假设 Web 服务 Add(添加)操作需要两个整数参数。以下代码将异步调用 Web 服务。

  MathProxy wsMath = new MathProxy();
  wsMath.BeginAdd(10, 15, null, null);

  调用 BeginAdd 并不会直接调用 Web 服务,而是对实际的 Web 服务调用进行排队,然后立即返回。调用返回时,Web 服务本身不提供任何信息,而是返回一个 IAsyncResult 引用,用于检索实际 Web 服务调用的结果。

class MyCalcForm : Form
{
private IAsyncResult _addAsyncResult ;
private MathProxy _wsMath = new MathProxy() ;
public void btnAdd_OnClick(object sender, EventArgs e)
{
_addAsyncResult = _wsMath.BeginAdd(10, 15, null, null) ;
}

  IAsyncResult 使应用程序能够确定调用完成的时间,并且可以检索调用结果。将 IAsyncResult 存储为类成员后,应用程序即可调用与启动时不同的方法,检索 Web 服务的调用结果。 

  为了检索 Web 服务的结果,应用程序调用代理的“End”方法,传递前面返回的 IAsyncResult,如以下代码所示。

  int sum = _wsMath.EndAdd(_addAsyncResult) ;

  “End”方法返回 Web 服务的返回值以及任何 ref (ByRef) 或 out 参数。 

  确定异步 Web 服务调用完成的时间

  应用程序必须先确定调用已经完成,然后才能检索异步 Web 服务调用的结果。应用程序可以选择完成时通知应用程序、中断等待完成或轮询三种方式确定 Web 服务是否完成。

 通知

  大多数情况下,通知是最佳选择,因为它允许应用程序启动对 Web 服务的调用,然后不需要任何特殊处理即可继续进行。Web 服务启动后,应用程序向“Begin”方法传递一个 AsyncCallback 委托。Web 服务调用完成后,将自动调用该委托。使用通知时,不需要存储“Begin”方法返回的 IAsyncResult,因为它将作为参数自动传递给通知委托。

class MyCalcForm : Form
{
private MathProxy _wsMath = new MathProxy();
public int _sum;
public void btnAdd_OnClick(object sender, EventArgs e)
{
AsyncCallback cb = new AsyncCallback(OnAddComplete);
_wsMath.BeginAdd(10, 15, cb, null); // 初始化 XML Web Service 调用
}
public OnAddComplete(IAsyncResult ar) // 完成后由框架调用
{
_sum = _wsMath.EndAdd(ar); // 获取 XML Web Service 结果
}

  警告:委托调用的方法在后台线程而不是主应用程序线程中运行。因此,委托方法无法安全地影响用户界面。有关详细信息,请参阅本文后面的“后台处理和用户体验”一节。

  中断

  有些情况下,应用程序在返回 Web 服务结果之前,只能执行一部分工作。在这种情况下,最好是先启动 Web 服务,执行工作中不依赖于 Web 服务结果的部分,然后中断,等待 Web 服务完成。IAsyncResult.AsyncWaitHandle 即提供了此功能。Web 服务调用启动后,AsyncWaitHandle 处于未收到信号状态,当 Web 服务调用完成后,AsyncWaitHandle 将收到信号。使用 AsyncWaitHandle 中的 WaitOne 方法会导致调用线程(通常为主应用程序线程)中断,直到 Web 服务完成。

public void DoCalculations()
{
IAsyncResult ar = _wsMath.BeginAdd(10, 15, null, null);
// 执行不需要 Add(添加)操作结果的工作
ar.AsyncWaitHandle.WaitOne() ; // 中断,直到调用完成
int sum = _wsMath.EndAdd(ar) ; // 检索结果
// 继续处理
}

  轮询

  少数情况下,应用程序可能希望一边进行处理,一边周期性地检查 Web 服务调用。使用 IAsyncResult.IsCompleted,应用程序可以确定 Web 服务调用是否完成。

IAsyncResult ar = _wsMath.BeginAdd(10, 15, null, null);
While (! ar.IsCompleted) // 循环,直到调用完成
{
// 等待时执行其他工作
}
int sum = _wsMath.EndAdd(ar) ; // 检索结果

  线程池

  当应用程序需要执行长时间运行的本地进程(例如很长的计算、文件处理或初始化)时,可以利用 .net Framework 精简版提供的内置线程池。线程池允许在后台运行多个工作,而不需要为每个任务频繁地创建和销毁单独的线程,从而减少了开销。

  .NET Framework 精简版线程池通过 ThreadPool 类提供。通过将一个方法打包到 WaitCallback 委托中,然后将该委托传递给 ThreadPool.QueueUserWorkItem 静态方法,在线程池中对任务进行排队。

void ReadBigFile(object val) 
{
// 执行读取和处理文件的操作
}

public void btnStartRead_Click(object sender, EventArgs e)
{
// 将 ReadBigFile 打包到委托中并提交给线程池
WaitCallback w = new WaitCallback(ReadBigFile) ;
ThreadPool.QueueUserWorkItem(w) ; 
}

  在上面的示例中,ReadBigFile 方法将在线程池中排队并在一个可用的线程上运行。对 QueueUserWorkItem 的调用将中断,直到将请求放入队列中。

  当要向后台进程传递参数时,QueueUserWorkItem 将提供一个重载,该重载接受一个附加参数,然后将其传递给已排队的方法。该参数被定义为对象,因而可以传递任何类型的参数。

void ReadBigFile2(object val) 
{
string dataFile = (string) val ; // val 是对 fName 的引用
// 执行读取和处理 dataFile 的操作
}

public void btnStartRead_Click(object sender, EventArgs e)
{
string fName = "BigDataFile.xml" ;
WaitCallback w = new WaitCallback(ReadBigFile2) ;
// fName 将被传递给 ReadBigFile
ThreadPool.QueueUserWorkItem(w, fName) ; 
}