`
coollifer
  • 浏览: 55629 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

使用异步方式调用同步方法

    博客分类:
  • .Net
 
阅读更多

 

使用异步方式调用同步方法

 

.NET Framework 4
0(共 1)对本文的评价是有帮助 - 评价此主题

 

 

.NET Framework 允许您异步调用任何方法。 为此,应定义与您要调用的方法具有相同签名的委托;公共语言运行时会自动使用适当的签名为该委托定义 BeginInvoke 和 EndInvoke方法。

注意注意

.NET Compact Framework 中不支持异步委托调用,也就是 BeginInvoke 和 EndInvoke 方法。

BeginInvoke 方法启动异步调用。 该方法与您需要异步执行的方法具有相同的参数,还有另外两个可选参数。 第一个参数是一个 AsyncCallback 委托,该委托引用在异步调用完成时要调用的方法。 第二个参数是一个用户定义的对象,该对象将信息传递到回调方法。 BeginInvoke 立即返回,不等待异步调用完成。 BeginInvoke 返回一个 IAsyncResult,后者可用于监视异步调用的进度。

EndInvoke 方法检索异步调用的结果。 在调用 BeginInvoke 之后随时可以调用该方法。 如果异步调用尚未完成,则 EndInvoke 会一直阻止调用线程,直到异步调用完成。EndInvoke 的参数包括您需要异步执行的方法的 out 和 ref 参数(在 Visual Basic 中为 <Out> ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult

注意注意

Visual Studio 2005 中的 IntelliSense 功能显示 BeginInvoke 和 EndInvoke 的参数。 如果您没有使用 Visual Studio 或类似工具,或您使用的是带有 Visual Studio 2005 的 C#,请参见 异步编程概述 以获取为这些方法定义的参数的说明。

本主题中的代码示例演示了使用 BeginInvoke 和 EndInvoke 进行异步调用的四种常用方法。 调用 BeginInvoke 之后,您可以执行下列操作:

  • 进行某些操作,然后调用 EndInvoke 一直阻止到调用完成。

  • 使用 IAsyncResult.AsyncWaitHandle 属性获取 WaitHandle,使用其 WaitOne 方法阻止执行,直至 WaitHandle 收到信号,然后调用 EndInvoke

  • 轮询由 BeginInvoke 返回的 IAsyncResult,以确定异步调用何时完成,然后调用 EndInvoke

  • 将用于回调方法的委托传递给 BeginInvoke 异步调用完成后,将在 ThreadPool 线程上执行该方法。 回调方法调用 EndInvoke

重要说明重要事项

无论您使用何种方法,都要调用 EndInvoke 来完成异步调用。

下面的代码示例演示异步调用同一个长时间运行的方法 TestMethod 的各种方式。 TestMethod 方法会显示一条控制台消息,说明该方法已开始处理,休眠了几秒钟,然后结束。TestMethod 有一个 out 参数,用于说明此类参数添加到 BeginInvoke 和 EndInvoke 的签名中的方式。 您可以按同样的方式处理 ref 参数。

下面的代码示例演示 TestMethod 的定义和名为 AsyncMethodCaller 的、可用来异步调用 TestMethod 的委托。 若要编译代码示例,必须包括 TestMethod 的定义和AsyncMethodCaller 委托。

using System;
using System.Threading; 

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncDemo 
    {
        // The method to be executed asynchronously.
        public string TestMethod(int callDuration, out int threadId) 
        {
            Console.WriteLine("Test method begins.");
            Thread.Sleep(callDuration);
            threadId = Thread.CurrentThread.ManagedThreadId;
            return String.Format("My call time was {0}.", callDuration.ToString());
        }
    }
    // The delegate must have the same signature as the method
    // it will call asynchronously.
    public delegate string AsyncMethodCaller(int callDuration, out int threadId);
}


异步执行方法的最简单方式是通过调用委托的 BeginInvoke 方法来开始执行方法,在主线程上执行一些操作,然后调用委托的 EndInvoke 方法。 EndInvoke 可能会阻止调用线程,因为该方法直到异步调用完成后才返回。 这种方式非常适合执行文件或网络操作。

重要说明 重要事项

因为 EndInvoke 可能会阻塞,所以不应从服务于用户界面的线程调用该方法。

using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        public static void Main() 
        {
            // The asynchronous method puts the thread id here.
            int threadId;

            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

            // Initiate the asychronous call.
            IAsyncResult result = caller.BeginInvoke(3000, 
                out threadId, null, null);

            Thread.Sleep(0);
            Console.WriteLine("Main thread {0} does some work.",
                Thread.CurrentThread.ManagedThreadId);

            // Call EndInvoke to wait for the asynchronous call to complete,
            // and to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, result);

            Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

/* This example produces output similar to the following:

Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
 */


您可以使用由 BeginInvoke 返回的 IAsyncResult 的 AsyncWaitHandle 属性来获取 WaitHandle 异步调用完成时,WaitHandle 会收到信号,您可以通过调用 WaitOne 方法等待它。

如果您使用 WaitHandle,则在异步调用完成之前或之后,但在通过调用 EndInvoke 检索结果之前,还可以执行其他处理。

注意 注意

调用 EndInvoke 时不会自动关闭等待句柄。 如果释放对等待句柄的所有引用,则当垃圾回收功能回收等待句柄时,将释放系统资源。 若要在等待句柄使用完毕后立即释放系统资源,请调用 WaitHandle.Close 方法来释放等待句柄。 显式释放可释放的对象时,垃圾回收的工作效率会更高。

using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        static void Main() 
        {
            // The asynchronous method puts the thread id here.
            int threadId;

            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

            // Initiate the asychronous call.
            IAsyncResult result = caller.BeginInvoke(3000, 
                out threadId, null, null);

            Thread.Sleep(0);
            Console.WriteLine("Main thread {0} does some work.",
                Thread.CurrentThread.ManagedThreadId);

            // Wait for the WaitHandle to become signaled.
            result.AsyncWaitHandle.WaitOne();

            // Perform additional processing here.
            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, result);

            // Close the wait handle.
            result.AsyncWaitHandle.Close();

            Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

/* This example produces output similar to the following:

Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
 */


您可以使用由 BeginInvoke 返回的 IAsyncResult 的 IsCompleted 属性来发现异步调用何时完成。 从用户界面的服务线程中进行异步调用时可以执行此操作。 轮询完成允许调用线程在异步调用在 ThreadPool 线程上执行时继续执行。

using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        static void Main() {
            // The asynchronous method puts the thread id here.
            int threadId;

            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

            // Initiate the asychronous call.
            IAsyncResult result = caller.BeginInvoke(3000, 
                out threadId, null, null);

            // Poll while simulating work.
            while(result.IsCompleted == false) {
                Thread.Sleep(250);
                Console.Write(".");
            }

            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, result);

            Console.WriteLine("\nThe call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

/* This example produces output similar to the following:

Test method begins.
.............
The call executed on thread 3, with return value "My call time was 3000.".
 */


如果启动异步调用的线程不需要是处理结果的线程,则可以在调用完成时执行回调方法。 回调方法在 ThreadPool 线程上执行。

若要使用回调方法,必须将表示回调方法的 AsyncCallback 委托传递给 BeginInvoke 也可以传递包含回调方法要使用的信息的对象。 在回调方法中,可以将 IAsyncResult(回调方法的唯一参数)强制转换为 AsyncResult 对象。 然后,可以使用 AsyncResult.AsyncDelegate 属性获取已用于启动调用的委托,以便可以调用 EndInvoke

有关示例的说明:

  • TestMethod 的 threadId 参数为 out 参数(在 Visual Basic 中为 <Out> ByRef),因此 TestMethod 从不使用该参数的输入值。 会将一个虚拟变量传递给 BeginInvoke 调用。 如果 threadId 参数为 ref 参数(在 Visual Basic 中为 ByRef),则该变量必须为类级别字段,这样才能同时传递给 BeginInvoke 和 EndInvoke

  • 传递给 BeginInvoke 的状态信息是一个格式字符串,回调方法使用该字符串来设置输出消息的格式。 因为作为类型 Object 进行传递,所以状态信息必须强制转换为正确的类型才能被使用。

  • 回调在 ThreadPool 线程上执行。 ThreadPool 线程是后台线程,这些线程不会在主线程结束后保持应用程序的运行,因此示例的主线程必须休眠足够长的时间以便回调完成。

using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        static void Main() 
        {
            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

            // The threadId parameter of TestMethod is an out parameter, so
            // its input value is never used by TestMethod. Therefore, a dummy
            // variable can be passed to the BeginInvoke call. If the threadId
            // parameter were a ref parameter, it would have to be a class-
            // level field so that it could be passed to both BeginInvoke and 
            // EndInvoke.
            int dummy = 0;

            // Initiate the asynchronous call, passing three seconds (3000 ms)
            // for the callDuration parameter of TestMethod; a dummy variable 
            // for the out parameter (threadId); the callback delegate; and
            // state information that can be retrieved by the callback method.
            // In this case, the state information is a string that can be used
            // to format a console message.
            IAsyncResult result = caller.BeginInvoke(3000,
                out dummy, 
                new AsyncCallback(CallbackMethod),
                "The call executed on thread {0}, with return value \"{1}\".");

            Console.WriteLine("The main thread {0} continues to execute...", 
                Thread.CurrentThread.ManagedThreadId);

            // The callback is made on a ThreadPool thread. ThreadPool threads
            // are background threads, which do not keep the application running
            // if the main thread ends. Comment out the next line to demonstrate
            // this.
            Thread.Sleep(4000);

            Console.WriteLine("The main thread ends.");
        }

        // The callback method must have the same signature as the
        // AsyncCallback delegate.
        static void CallbackMethod(IAsyncResult ar) 
        {
            // Retrieve the delegate.
            AsyncResult result = (AsyncResult) ar;
            AsyncMethodCaller caller = (AsyncMethodCaller) result.AsyncDelegate;

            // Retrieve the format string that was passed as state 
            // information.
            string formatString = (string) ar.AsyncState;

            // Define a variable to receive the value of the out parameter.
            // If the parameter were ref rather than out then it would have to
            // be a class-level field so it could also be passed to BeginInvoke.
            int threadId = 0;

            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, ar);

            // Use the format string to format the output message.
            Console.WriteLine(formatString, threadId, returnValue);
        }
    }
}

/* This example produces output similar to the following:

The main thread 1 continues to execute...
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
The main thread ends.
 */


分享到:
评论

相关推荐

    Java异步调用转同步方法实例详解

    Java中将异步调用转换为同步调用有多种方法,本文将详细介绍五种方法:使用wait和notify方法、使用条件锁、使用Future、使用CountDownLatch、使用CyclicBarrier。 1. 使用wait和notify方法 wait和notify方法是...

    Nodejs让异步变成同步的方法

    Node.js中让异步操作变成同步的方法通常是指将非阻塞的异步调用改写为在逻辑上表现得像同步调用的方式。Node.js中异步操作是通过回调函数、Promises和async/await等技术来实现的。以下我们详细讲解如何通过这些方法...

    Angular异步变同步处理方法

    Angular异步变同步处理方法是前端开发中用于解决多个接口请求顺序依赖问题的一种技术手段。由于异步操作的特性,它能处理那些按顺序依次执行的接口调用,而不会阻塞主线程,让页面陷入假死状态。在Angular中,主要...

    C#同步调用,异步调用,异步回调.docx

    在 C# 编程中,调用方法可以分为同步调用和异步调用两种。同步调用是指当前线程阻塞,等待方法执行完毕后继续执行,而异步调用则是将方法调用交给线程池,当前线程继续执行不阻塞。异步调用可以使用 BeginInvoke 和 ...

    WebService同步异步调用示例代码.rar

    在这个"WebService同步异步调用示例代码.rar"压缩包中,我们很可能找到C#语言编写的源代码,这些代码演示了如何使用.NET框架来创建和消费WebService,特别是在同步和异步模式下进行调用的方法。 同步调用是最基础的...

    Labview异步调用示例

    5. **异步编程的最佳实践**:为了有效地使用异步调用,开发者应遵循一些最佳实践,如合理设计回调函数,避免死锁和竞态条件,以及正确管理资源,确保程序的稳定性和可维护性。 在提供的“异步调用示例”压缩包中,...

    LabVIEW中异步调用+可重入VI设置

    在LabVIEW中,可以通过创建事件结构和使用回调VI来实现异步调用。例如,你可以创建一个事件结构来监听特定的用户交互或硬件事件,当这些事件发生时,对应的回调VI会被异步调用执行。 接下来,我们讨论可重入VI。可...

    同步方法和异步方法比较

    在编程领域,同步和异步方法是处理任务执行方式的两种基本模式,它们在系统设计和性能优化中扮演着至关重要的角色。理解这两者的区别及其优缺点对于开发高效的应用至关重要。 **同步方法**指的是调用一个函数或方法...

    C#异步调用的好处和方法

    ### C#中的异步调用:好处与方法 在现代软件开发中,特别是在涉及大量数据处理、网络请求或用户交互的应用程序中,异步编程变得越来越重要。C#作为一种广泛使用的编程语言,提供了多种实现异步操作的方式。本文将...

    asp.net异步调用后台方法提交

    ### ASP.NET 异步调用后台方法提交 在ASP.NET开发中,为了提升用户体验和页面响应速度,异步调用后台方法是一种常见的技术手段。本文将详细介绍如何在ASP.NET中实现异步调用后台方法,并解释相关的代码实现细节。 ...

    Winform通用异步界面调用

    2. **委托与事件**:在异步调用中,委托扮演了关键角色。它们是类型安全的函数指针,可以作为参数传递给其他方法。`TestAsyncViewForm`可能定义了一些事件处理程序,如`ProgressChanged`,并通过委托将这些事件绑定...

    Winform界面异步调用

    在.NET Framework中,可以使用多种方式实现Winform界面的异步调用: 1. **BackgroundWorker组件**:这是.NET Framework提供的一种简单易用的异步模型。通过创建BackgroundWorker对象,设置其DoWork事件处理程序执行...

    Labview2015多线程异步调用工程

    异步调用是一种非阻塞的调用方式,它允许主线程在等待子线程完成任务的同时,继续执行其他工作。在Labview中,可以通过事件结构或回调函数来实现异步调用。在这个工程中,主线程通过发送任务到子线程,然后继续其...

    WCF 同步 异步调用 实例

    在服务接口中,每个同步操作都有对应的`BeginXXX`和`EndXXX`方法用于异步调用。例如,对于`GetData`方法,会有`BeginGetData`和`EndGetData`。 ```csharp using (ServiceReference1.Service1Client client = new ...

    AsyncCalls(异步调用函数)

    1. **异步方法调用**:异步调用函数允许你将一个方法的调用包装成一个异步任务,然后在后台线程执行。这样,主线程可以继续处理其他任务,而不会被长时间运行的操作阻塞。 2. **事件处理**:在异步操作完成后,通常...

    c#中的异步调用

    本文将深入探讨C#中的异步调用,包括基础概念、委托、Task类以及async/await关键字的使用。 首先,我们了解异步编程的基本理念。传统的同步编程模型中,代码按照顺序执行,如果某个操作需要花费大量时间,整个程序...

    异步调用流程图

    首先,异步调用的基本思想是,当一个函数或方法被调用时,它并不立即返回结果,而是立即返回一个代表未来结果的对象(如Promise或Future)。调用者可以继续执行后续任务,而不会等待该异步操作完成。当异步操作的...

    多线程异步调用(并参递参数)

    下面是一个使用Python的`concurrent.futures`模块实现多线程异步调用(并参递参数)的示例: ```python import concurrent.futures def long_running_task(param1, param2): # 这里是耗时操作 result = param1 +...

Global site tag (gtag.js) - Google Analytics