如何以异步方式调用 Visual C# 方法

文章翻译 文章翻译
文章编号: 315582 - 查看本文应用于的产品
展开全部 | 关闭全部

本文内容

概要

Microsoft.NET Framework 容易以异步方式调用的函数。以异步方式调用函数将导致系统调用函数继续进行其他工作的同时在后台辅助线程上执行。在典型 (同步) 的函数调用中,函数被执行调用的相同线程上立即执行。调用函数等待调用完成,并接收在继续操作之前调用的结果。与此相反,当进行异步调用时,您检索以后异步调用的结果。本文演示如何使用 Visual C# 执行此操作。

要求


下面的列表列出了推荐使用的硬件、 软件、 网络基础结构和所需的服务包:
  • Microsoft Windows 2000 或 Windows XP 或 Windows Server 2003
  • Visual Studio.NET 或 Visual Studio 2005
本文假定您熟悉下列主题:
  • 调用方法 Visual C#
  • 如何使用委托

如何进行异步调用

通过使用委托进行异步调用。委托是包装函数的对象。委托提供的同步函数,并且还提供了异步调用包装的函数的方法。这些方法为BeginInvoke()EndInvoke()。这些方法中的参数列表因委托将包装函数的签名。请注意 Visual Studio.NET IntelliSense 功能未显示BeginInvoke()EndInvoke(),您看不到它们在您键入时显示在函数列表中。

BeginInvoke()用于启动异步调用。它具有相同的参数换行功能,再加上将在本文稍后部分中所述的两个附加参数。BeginInvoke()将立即返回,不会等待异步调用完成。BeginInvoke()返回一个IAsyncResult对象。

使用EndInvoke()函数来检索异步调用的结果。BeginInvoke()后随时可以调用它。如果异步调用尚未完成, EndInvoke()块直到它完成。EndInvoke()函数的参数包括 ref 有包装的函数,加上由BeginInvoke()IAsyncResult对象的参数。

下面是一个委托,它BeginInvoke()EndInvoke()的方法的示例:
// The following delegate 
delegate string MethodDelegate(int iCallTime, out int iExecThread)  ;

// will have the following BeginInvoke() and EndInvoke methods:
IAsyncResult MethodDelegate.BeginInvoke(int iCallTime, out int iExecThread, AsyncCallback cb, object AsyncState); 

string MethodDelegate.EndInvoke (out int iExecThread, IAsyncResult ar) ;
				
有四种常用的方法,可以使用BeginInvoke()EndInvoke()进行异步调用。在您调用BeginInvoke()之后,您可以:
  • (可选) 执行一些其他操作,然后使用EndInvoke()
  • 获取WaitHandle所提供的IAsyncResult对象,其WaitOne方法用于阻止WaitHandle处于终止状态,直到然后调用EndInvoke()
  • 轮询的IAsyncResult对象,以确定异步调用完成后,然后调用EndInvoke()
  • 使系统调用指定的回调函数。此回调函数调用EndInvoke()和流程的异步结果时调用 itcompletes。
下面的代码示例演示了这些调用模式,对比它们与进行同步调用使用以下函数:
string LongRunningMethod (int iCallTime, out int iExecThread)
{
	Thread.Sleep (iCallTime) ;
	iExecThread = AppDomain.GetCurrentThreadId ();
	return "MyCallTime was " + iCallTime.ToString() ;
}

				
LongRunningMethod()模拟长时间运行的休眠功能。它将返回的睡眠时间和执行它的线程的 ID。如果异步调用,您发现正在执行的线程的线程 ID 是不同于调用线程。

第一步是定义函数的委托:
delegate string MethodDelegate(int iCallTime, out int iExecThread)  ;
				

示例 1: 同步调用的方法

此示例演示如何通过使用MethodDelegate委托的同步调用LongRunningMethod() 。其他示例对比这由以异步方式进行联络。
  1. 开始 Microsoft Visual Studio.NET 或 Microsoft Visual Studio 2005年。
  2. 创建新的可视 C# 控制台应用程序项目 namedAsyncDemo。
  3. 添加一个名为 AsyncDemo 到新的.cs 文件中的项目,如下所示定义类:
    using System;
    using System.Threading ; 
    using System.Windows.Forms ;
    
    public class AsyncDemo
    {
    	string LongRunningMethod (int iCallTime, out int iExecThread)
    	{
    		Thread.Sleep (iCallTime) ;
    		iExecThread = AppDomain.GetCurrentThreadId ();
    		return "MyCallTime was " + iCallTime.ToString() ;
    	}
    
    	delegate string MethodDelegate(int iCallTime, out int iExecThread)  ;
    
    	public void DemoSyncCall()
    	{
    		string s ;
    		int iExecThread;
    
    		// Create an instance of a delegate that wraps LongRunningMethod.
    		MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;  
    			
    		// Call LongRunningMethod using the delegate.
    		s = dlgt(3000, out iExecThread);  
    			
    		MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", 
                                            and the thread ID {1}", s, iExecThread.ToString() ) );
    	}
    }
    					
    稍后,此类演示如何进行异步调用。最初,但是,它只包含演示如何调用 delegatesynchronously 的DemoSyncCall()方法。
  4. 在 Visual Studio 自动创建在您的项目中的Main函数的正文中添加以下代码:
    static void Main(string[] args)
    {
    	AsyncDemo ad = new AsyncDemo () ;
    	ad.DemoSyncCall() ;
    }
    					
  5. 按 CTRL + F5 以运行应用程序。

示例 2: 异步调用方法使用EndInvoke()调用模式

在此部分中,该示例异步调用同一个方法。用于调用模式是调用BeginInvoke,进行某些操作主线程上,然后调用EndInvoke()。请注意, EndInvoke()不返回直到异步调用完成为止。此调用模式非常有用时要调用的线程正在执行异步调用时工作正常。有在同一时间发生的工作可以提高许多应用程序的性能。常见任务以异步方式运行,以这种方式的文件或网络操作。
  1. 添加一个名为DemoEndInvoke()AsyncDemo类的方法。DemoEndInvoke函数演示如何异步调用该委托。
    public void DemoEndInvoke()
    {
    	MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    	string s ;
    	int iExecThread;
    
    	// Initiate the asynchronous call.
    	IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null);  
    
    	// Do some useful work here. This would be work you want to have
    	// run at the same time as the asynchronous call.
    
    	// Retrieve the results of the asynchronous call.
    	s = dlgt.EndInvoke (out iExecThread, ar) ;  
    
    	MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", 
                                   and the number {1}", s, iExecThread.ToString() ) );
    }
    					
  2. 对于编辑源代码,以使其包含以下代码:
    static void Main(string[] args)
    {
    	AsyncDemo ad = new AsyncDemo () ;
    	ad.DemoEndInvoke() ;
    }
    					
  3. 按 CTRL + F5 以运行应用程序。

示例 3: 异步调用方法,并使用 WaitHandle 到等待调用完成


在本节中,示例异步调用该方法,调用EndInvoke()之前等待WaitHandle 。由BeginInvoke()IAsyncResult有一个AsyncWaitHandle属性。此属性返回WaitHandle当异步调用完成时终止。WaitHandle等待是一种常用的线程同步技术。调用线程在等待WaitHandle上使用WaitHandleWaitOne()方法。WaitOne()块直到WaitHandle处于终止状态。WaitOne()返回时,您可以执行一些附加工作,才能调用EndInvoke()。如在上面的示例中,此方法可用于执行文件或网络操作,否则将阻止调用主线程。
  1. 添加一个名为DemoWaitHandle()AsyncDemo类的函数。DemoWaitHandle()函数演示如何异步调用该委托。
    public void DemoWaitHandle ()
    {
    	string s ;
    	int iExecThread;
    
    	MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    
    	// Initiate the asynchronous call.
    	IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null); 
    
    	// Do some useful work here. This would be work you want to have
    	// run at the same time as the asynchronous call.
    
    	// Wait for the WaitHandle to become signaled.
    	ar.AsyncWaitHandle.WaitOne() ;
    
    	// Get the results of the asynchronous call.
    	s = dlgt.EndInvoke (out iExecThread, ar) ;
    			
    	MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", 
                                     and the number {1}", s, iExecThread.ToString() ) );
    }
    					
  2. 对于编辑源代码,以使其包含以下代码:
    static void Main(string[] args)
    {
    	AsyncDemo ad = new AsyncDemo () ;
    	ad.DemoWaitHandle () ;
    }
    					
  3. 按 CTRL + F5 以运行应用程序。

示例 4: 异步调用方法通过使用轮询调用模式

在本节中,示例轮询异步调用完成时,找出的IAsyncResult对象。由BeginInvoke()IAsyncResult对象均具有完成属性异步调用完成后返回,则返回 True 。然后,您可以调用EndInvoke()。此调用模式是很有用的如果您的应用程序,您不希望被长时间运行的函数调用具有阻止正在进行的工作。Microsoft Windows 应用程序是一个例子。Windows 应用程序的主线程可以继续处理用户输入,而执行异步调用。它可以定期检查以查看是否已完成该调用完成。它会调用EndInvoke完成,则返回True。因为EndInvoke()阻止异步操作完成之前,应用程序不调用它之前知道该操作已完成。
  1. 添加一个名为DemoPolling()AsyncDemo类的函数。DemoPolling()函数演示如何异步调用该委托 anduse 轮询,以完成此过程后,请参阅。
    public void DemoPolling()
    {
    	MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    	string s ;
    	int iExecThread;
    
    	// Initiate the asynchronous call.
    	IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null); 
    
    	// Poll IAsyncResult.IsCompleted
    	while(ar.IsCompleted == false)
    	{
    		Thread.Sleep (10) ;  // pretend to so some useful work
    	}
    	s = dlgt.EndInvoke (out iExecThread, ar) ;
    
    	MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", 
                                    and the number {1}", s, iExecThread.ToString() ) );
    }
    
    					
  2. 编辑源代码。函数的内容替换为以下代码:
    static void Main(string[] args)
    {
    	AsyncDemo ad = new AsyncDemo () ;
    	ad.DemoPolling () ;
    }
    					
  3. 按 CTRL + F5 以运行应用程序。

示例 5: 在异步方法完成时执行回调

在此部分中,该示例提供对系统执行异步调用完成时的BeginInvoke()函数的回调委托。回调调用EndInvoke()并处理异步调用的结果。此调用模式是很有用的如果启动异步调用的线程不需要处理该调用的结果。在异步调用完成时,系统将调用的回调在启动线程以外的线程上。

若要使用此调用模式,必须将异步回调操作类型的委托,作为BeginInvoke()函数的倒数第二个参数进行传递。BeginInvoke()还有最后一个参数的类型可以将任何对象传递到该对象。被调用时,该对象是可用于您的回调函数。此参数的一个重要应用是传递给用于启动调用该委托。回调函数可以使用该委托的EndInvoke()函数来完成调用。下面演示此调用模式。
  1. 添加到AsyncDemo类中名为DemoCallback()MyAsyncCallback()两种方法。DemoCallback()方法演示如何异步调用该委托。Ituses 委托来包装MyAsyncCallback()方法中,系统在调用时异步 operationcompletes。MyAsyncCallback()调用EndInvoke()
    public void DemoCallback()
    {
    	MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    	string s ;
    	int iExecThread;
    
    	// Create the callback delegate.
    	AsyncCallback cb = new AsyncCallback(MyAsyncCallback);
    
    	// Initiate the Asynchronous call passing in the callback delegate
    	// and the delegate object used to initiate the call.
    	IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, cb, dlgt); 
    }
    
    public void MyAsyncCallback(IAsyncResult ar)
    {
    	string s ;
    	int iExecThread ;
    
    	// Because you passed your original delegate in the asyncState parameter
    	// of the Begin call, you can get it back here to complete the call.
    	MethodDelegate dlgt = (MethodDelegate) ar.AsyncState;
    
    	// Complete the call.
    	s = dlgt.EndInvoke (out iExecThread, ar) ;
    
    	MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", 
                                    and the number {1}", s, iExecThread.ToString() ) );
    }
    
    					
  2. 编辑源代码。函数的内容替换为以下代码:
    static void Main(string[] args)
    {
    	AsyncDemo ad = new AsyncDemo () ;
    	ad.DemoCallback() ;
    }
    					
  3. 按 CTRL + F5 以运行应用程序。

属性

文章编号: 315582 - 最后修改: 2014年2月9日 - 修订: 7.0
这篇文章中的信息适用于:
  • Microsoft Visual Studio .NET 2002 专业版
  • Microsoft Visual C# .NET 2002 标准版
  • Microsoft Visual C# 2005 Express Edition
关键字:?
kbhowtomaster kbmt KB315582 KbMtzh
机器翻译
重要说明:本文是由 Microsoft 机器翻译软件进行的翻译并可能由 Microsoft 社区通过社区翻译机构(CTF)技术进行后期编辑,或可能是由人工进行的翻译。Microsoft 同时向您提供机器翻译、人工翻译及社区后期编辑的文章,以便对我们知识库中的所有文章以多种语言提供访问。翻译的文章可能存在词汇、句法和/或语法方面的错误。Microsoft 对由于内容的误译或客户对内容的使用所导致的任何不准确、错误或损失不承担责任。
点击这里察看该文章的英文版: 315582
Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、间接的、衍生性的损害或任何因使用而丧失所导致的之损害、数据或利润不负任何责任。

提供反馈

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com