csharp 异步编程

csharp 异步编程

当有多个任务需要同时执行,或者有比较费事的操作时但不想阻塞主线程的时候,我们往往会使用到多线程编程,但是多线程编程本身需要很强的
多线程编程思维,需要解决诸多问题:如线程锁、线程间的数据同步等问题。csharp提供了异步编程的模式,.net提供了三种模式:基于任务的
异步编程(TAP)、基于事件的异步编程(EAP)、异步编程模式(APM)三种模式

TAP

csharp虽然提供了三种不同的异步编程的模式,但是相对于EAP和APM,TAP使用起来更简单易用,TAP是基于task的异步编程模式,使用一个方
法就能完成所有的操作。从代码阅读角度去看,TAP的整理逻辑和同步的逻辑基本一样。具体的EAP和APM使用方式可以参见下面的介绍,它们都涉
及到多个方法,才能完成异步操作。当异步操作比较多的时候,EAP和APM都会会陷入callback hell。

我们在设计游戏中的新手引导的时候,经常会有一些强制引导。比如下面的流程:

走到A点
打包宝箱
打包背包
使用物品

以前设计的时候,我们可能使用event设计模式,通过事件的监听与发布来解决此类问题。下面是一个伪代码,真实的设计中并不会真的这么设计,
这里只是为了说明callback hell的问题。下面的代码我们都是放在了guid类中,可能看起来还不算复杂,有的会将各事件的处理分布在不同的
函数中,这时就更头痛了。

public class Guild
{
    public Guild()
    {
        evnet.register("onPlayMove", onPlayMove);
        evnet.register("onGetBox", onGetBox);
        //...
    }

    public void Move(Vector3 postion)
    {
        //pick box.
    }
    
    public void onGetBox()
    {
        //open bag.
    }
}


当时我们使用TAP模式编程时,上面的问题就会变的简单。

public class Guild
{
    public async void DoTask()
    {
       await Player.Move(postion);
       await Player.PickItem();
       await openBag();
       await Player.UserItem();
       //....
    }
}

EAP

基于事件的异步模式,一般会有两个相应的API:MethodNameAsync和OnMethodNameCompleted.比如WebClient中的download相关的api

ManualResetEvent waitWeb = new ManualResetEvent(false);
WebClient webClient = new WebClient();
webClient.DownloadStringCompleted += (sender, eventArgs) =>
{
    Console.WriteLine("content length:{0}",eventArgs.Result.Length);
    Console.WriteLine("xxxx");
    waitWeb.Set();
};

webClient.DownloadStringAsync(new Uri("http://www.baidu.com"));
Console.WriteLine("start download");
waitWeb.WaitOne();
Console.WriteLine("over");

执行结果

start download
content length:9193
xxxx
over

APM

APM是基于IAsyncResult设计模式完成的异步操作,具体是通过命名为BeginOperationName和EndOperationName的两个方法来实现的。
begin和end分别用于开始和结束并获取异步结果。例如Action中一个对BeginInvoke和EndInvoke,以及strem中的BeginRead和EndRead
这些api都是基于APM模式设计的。

 public class Demo
    {
        public string Test(double seconds)
        {
            Console.WriteLine("Test Start");
            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            Console.WriteLine("Test End");

            return $"Test cost:{seconds}s";
        }
    }
    
    class Program
    {

        delegate string AsyncCall(double seconds);
        
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            Demo demo = new Demo();

            AsyncCall asyncCall = new AsyncCall(demo.Test);
            var asyncResult = asyncCall.BeginInvoke(5, null, null);\
            Console.WriteLine("main sleep");
            Thread.Sleep(1000);
            Console.WriteLine("main sleep end!");
            Console.WriteLine(asyncCall.EndInvoke(asyncResult));
            Console.WriteLine("goodby!");
        }
    }

执行结果

Hello World!
main sleep
Test Start
main sleep end!
Test End
Test cost:5s
goodby!

猜你喜欢

转载自blog.csdn.net/scdnshijiemengxiang/article/details/128730324
今日推荐