zoukankan      html  css  js  c++  java
  • C#多线程编程之:异步方法调用

    异步方法

      当一个线程调用方法后,直到方法执行完毕,线程才继续执行,这种方法被称为同步方法。然而,有些方法执行时间可能非常长,比如串口操作或访问网络,这样线程被阻塞,而无法响应用户的其他请求。这种情况通常是无法忍受的,所以这时我们应该使用异步方法。

      异步方法的原理是,在方法调用前为异步方法指定一个回调函数,方法调用后被线程池中的一个线程接管,执行该方法。主线程立即返回,继续执行其他工作或响应用户请求。如果异步方法执行完毕,回调函数被自动执行,以处理异步方法的调用结果。

      如何实现异步方法呢?C#通过异步委托调用BeginInvoke和EndInvoke方法来实现异步方法。

    BeginInvoke方法原型:

      IAsyncResult BeginInvoke(......, AsyncCallback callback, object o);
      ......表示异步委托中定义的参数列表。
      AsyncCallback参数是一个用于回调函数的委托,它的原型为:
      public delegate void AsyncCallback(IAsyncResult ar)。其中IAsyncResult参数用于包装异步方法的执行结果。
      Object参数用于在主线程与回调函数间传递一些附加信息,如同步信息。

    EndInvoke方法原型:

      xxx EndInvoke(IAsyncResult result);
      xxx表示异步委托原型中定义的返回数据类型,IAsyncResult用于包装异步方法的执行结果。

      这么看着是不是有点迷糊?看个例子就明白了:

    复制代码
    using System;
    using System.Threading;
    using System.Runtime.Remoting.Messaging;

    namespace ProcessTest
    {
    class Program
    {
    //异步调用执行完成同步信号
    static AutoResetEvent ev =new AutoResetEvent(false);
    //定义委托
    publicdelegateint Deleg(int a, int b);

    staticint WriteSum(int a, int b)
    {
    //显示当前线程ID号及Sum值
    Console.WriteLine("执行WriteSum的线程ID为:{0},Sum = {1}", Thread.CurrentThread.ManagedThreadId, a + b);
    return a + b;
    }

    //回调函数
    staticvoid SumDone(IAsyncResult async)
    {
    //等待1秒,模拟线程正在执行其他工作
    Thread.Sleep(1000);

    //async中包装了异步方法执行的结果
    //从操作结果async中还原委托
    Deleg proc = ((AsyncResult)async).AsyncDelegate as Deleg;
    //获取异步方法的执行结果
    int sum = proc.EndInvoke(async);

    //显示结果
    Console.WriteLine("执行SumDone的线程ID为:{0},Sum = {1}", Thread.CurrentThread.ManagedThreadId, sum);

    //使用AsnycState属性获取主线程中传入的同步信号
    //释放同步信号表示异步调用已完成
    ((AutoResetEvent)async.AsyncState).Set();


    }

    staticvoid Main(string[] args)
    {
    //创建一个委托
    Deleg proc =new Deleg(WriteSum);

    //采用异步方式调用委托
    //指定SumDone为异步操作完成后的回调函数
    //指定ev为object参数,用于同步回调函数与主线程间操作
    IAsyncResult async = proc.BeginInvoke(10, 10, SumDone, ev);
    Console.WriteLine(
    "主线程ID号为:{0},异步操作已开始执行,正等待操作完成。", Thread.CurrentThread.ManagedThreadId);

    //等待异步操作完成
    ev.WaitOne();
    Console.WriteLine(
    "异步操作已完成!");

    System.Console.ReadKey();
    }
    }
    }
    复制代码

     

      下图是程序的运行结果:

      

      注意观察运行结果,异步方法和回调函数是在同一步线程执行。

    为方法指定OneWay特性

      我们可将 System.Runtime.Remoting.Messaging.OneWay特性应用于任何一个方法,该特性告诉CLR该方法不返回任何信息。即 使该方法实际返回了数据(通过return语句或out、ref定义的参数),但只要被标记了OneWay特性,那它就不会再返回任何信息。

      一个被标记为OneWay特性的方法即可以同步方式调用,也可以异步方式调用。如果在它的执行过程中引起了一个异常却没有捕获,在同步方式下,该异常会向上传播;但在异步方式下,该异常将不会被传播。大多数情况下,被标记为OneWay的方法是以异步方式工作。

  • 相关阅读:
    XAML学习笔记之Layout(五)——ViewBox
    XAML学习笔记——Layout(三)
    XAML学习笔记——Layout(二)
    XAML学习笔记——Layout(一)
    从0开始搭建SQL Server 2012 AlwaysOn 第三篇(安装数据,配置AlwaysOn)
    从0开始搭建SQL Server 2012 AlwaysOn 第二篇(配置故障转移集群)
    从0开始搭建SQL Server 2012 AlwaysOn 第一篇(AD域与DNS)
    Sql Server 2012 事务复制遇到的问题及解决方式
    Sql Server 2008R2升级 Sql Server 2012 问题
    第一次ACM
  • 原文地址:https://www.cnblogs.com/mili3/p/3737482.html
Copyright © 2011-2022 走看看