• c# 异步和同步问题(转载)


    [C#] 谈谈异步编程async await

     

      为什么需要异步,异步对可能起阻止作用的活动(例如,应用程序访问 Web 时)至关重要。 对 Web 资源的访问有时很慢或会延迟。 如果此类活动在同步过程中受阻,则整个应用程序必须等待。 在异步过程中,应用程序可继续执行不依赖 Web 资源的其他工作,直至潜在阻止任务完成。

      本节将一步一步带领大家理解async和await。

      期间会有

      Hello World原理介绍异步会提高程序的运行速度吗async和awaitMVC中的异步Action,以及线程中常涉及到的线程安全信号量,以及微软提供的异步API

      推荐先看后顶,学的更快!

    Hello World

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    static void Main(string[] args)
    {
        new Thread(Test) { IsBackground = false }.Start();      //.Net 在1.0的时候,就已经提供最基本的API.
        ThreadPool.QueueUserWorkItem(o => Test());              //线程池中取空闲线程执行委托(方法)
        Task.Run((Action)Test);                                 //.Net 4.0以上可用
        Console.WriteLine("Main Thread");
        Console.ReadLine();
    }
     
    static void Test()
    {
        Thread.Sleep(1000);
        Console.WriteLine("Hello World");
    }

      

    原理

      其实不管是Task,ThreadPool,本质最终都是Thread。只不过微软帮我们在简化线程控制的复杂度。

      线程池是CLR中事先定义好的一些线程。Task取的线程池,只不过在语法上,可以非常方便取返回值。

    异步会提高程序的运行速度吗

      多线程会提高程序的效率,不会提高运行速度。

      这就好比这一个任务让前台花1个小时。前台完成10分钟的时候

      打电话给经理,让他安排一个人来干30分钟(new Thread()),他干剩下的20分钟。(创建线程,需要时间,内存资源)

      或者从旁边空闲的同事中(ThreadPool 或 Task),拉一个人过来干30分钟。他干剩下的20分钟。(需要的时间少,资源本来就存在)

      从上看出,异步会让一份任务时间变长。资源消耗更多。但是可以让前台(UI线程)空闲下来,听从领导(用户)指挥。

    async和await只是一个标记

      首先看个Demo,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    static void Main(string[] args)
    {
        Task.Run(() =>                                          //异步开始执行
        {
            Thread.Sleep(1000);                                 //异步执行一些任务
            Console.WriteLine("Hello World");                   //异步执行完成标记
        });
        Thread.Sleep(1100);                                     //主线程在执行一些任务
        Console.WriteLine("Main Thread");                       //主线程完成标记
        Console.ReadLine();
    }

      发现执行结果是:

      这个很正常。但是我们希望先执行主线程完成标记,不改动主线程和Task的任务情况下,如何处理?

    使用await和async

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    static void Main(string[] args)
    {
        Say();                             //由于Main不能使用async标记
        Console.ReadLine();
    }
    private async static void Say()
    {
        var t = TestAsync();
        Thread.Sleep(1100);                                     //主线程在执行一些任务
        Console.WriteLine("Main Thread");                       //主线程完成标记
        Console.WriteLine(await t);                             //await 主线程等待取异步返回结果
    }
    static async Task<string> TestAsync()
    {
        return await Task.Run(() =>
        {
            Thread.Sleep(1000);                                 //异步执行一些任务
            return "Hello World";                               //异步执行完成标记
        });
    }

      1.凡是使用await关键字的方法,都必须打上async标记。

      2.async表示方法内有异步方法,调用async方法,会立刻另起线程执行。

      3.await只是显示等待线程结束。await表示等待异步方法执行完,并取返回值。

    MVC中的异步Action

      既然多线程不能提高运行速度,而且每次请求Asp.net程序都是发起一个新的线程,为什么还要用多线程让其“降速”?

      为了提高网站的吞吐量。

      在MVC中,如果采用异步Action,则会像下面情况执行。

      1.请求到达IIS,IIS应用程序池分配一个worker线程用来响应请求。

      2.worker线程,执行异步操作,调用CLR线程池线程处理。

      3.释放worker线程,响应其他请求。

      4.异步操作执行完,w3wp(应用程序池进程)再次分配一个worker线程继续响应。

      上述使用场景中,会获取两次worker 线程,这两次获取的线程可能相同,也可能会不同。如果有比较耗时的任务,非常建议把同步请求转换为异步。

    线程安全和信号量

       先举个线程不安全的例子。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    static void Main(string[] args)
    {
        Task.Run((Action)Test);
        Task.Run((Action)Test);
        Console.ReadLine();
    }
     
    private static void Test()
    {
        if (!IsComplete)
        {
            //todo other
            Thread.Sleep(500);
            Console.WriteLine("执行完成");
            IsComplete = true;
        }
    }
     
    public static bool IsComplete { getset; }

      上面的执行结果,这就是线程不安全。(多线程访问同一段代码 产生不确定结果。)

      

    如何解决,涉及到线程锁的概念。线程锁会让多线程访问的时候,一次只允许一个线程进入。

    线程锁例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    private static readonly object lockObj = new object();
            public static bool IsComplete { getset; }
            static void Main(string[] args)
            {
                Task.Run((Action)Test);
                Task.Run((Action)Test);
                Console.ReadLine();
            }
     
            private static void Test()
            {
                lock (lockObj)                              //锁住的必须是引用类型。由于在静态方法中,则锁住静态引用类型。
                {
                    if (!IsComplete)
                    {
                        //todo other
                        Thread.Sleep(500);
                        Console.WriteLine("执行完成");
                        IsComplete = true;
                    }
                }
            }

      

    信号量

      线程锁的技术使一块代码只能一个线程进入。信号量的存在,则是让同一块代码指定多个线程进入。

    信号量(SemaphoreSlim)例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    static readonly SemaphoreSlim slim = new SemaphoreSlim(2);
            static void Main(string[] args)
            {
                for (int i = 0; i < 5; i++)
                {
                    ThreadPool.QueueUserWorkItem(Test, i);
                }
                Console.ReadLine();
            }
     
            private async static void Test(object i)
            {
                Console.WriteLine("准备执行" + i);
                await slim.WaitAsync();
                Console.WriteLine("开始执行" + i);
                //todo other
                await Task.Delay(1000);
                Console.WriteLine("执行结束" + i);
                slim.Release();
            }

    上面执行结果

    从 .NET Framework 4.5 和 Windows 运行时中列出的 API 包含支持异步编程的方法。

    应用程序区域

    包含异步方法的受支持的 API

    Web 访问

    HttpClientSyndicationClient

    使用文件

    StorageFileStreamWriterStreamReaderXmlReader

    使用图像

    MediaCaptureBitmapEncoderBitmapDecoder

    WCF 编程

    同步和异步操作

    作者:Never、C

    本文链接:http://www.cnblogs.com/neverc/p/4368821.html

  • 相关阅读:
    zoj 2316 Matrix Multiplication 解题报告
    BestCoder7 1001 Little Pony and Permutation(hdu 4985) 解题报告
    codeforces 463C. Gargari and Bishops 解题报告
    codeforces 463B Caisa and Pylons 解题报告
    codeforces 463A Caisa and Sugar 解题报告
    CSS3新的字体尺寸单位rem
    CSS中文字体对照表
    引用外部CSS的link和import方式的分析与比较
    CSS样式表引用方式
    10个CSS简写/优化技巧
  • 原文地址:https://www.cnblogs.com/LoveAndPeace/p/7124830.html
Copyright © 2020-2023  润新知