• .Net 线程&异步


    引子

    今天遇到一个简单的问题,一个获取下载文件的接口,本来是要在判断文件不存在的情况下重新生成的,但是因为重新生成需要的时间比较长,因此就考虑,当文件不存在的时候开启一个后台线程,而直接返回错误,让重试,这样体验会好一点。

    代码如下

    string filePath = "";
    if (File.Exists(filePath)) return true;
    Task.Run(() =>
    {
        // 执行生成文件的操作
    });
    return false;

    这里的Task.Run()就是启动一个后台线程,不会影响主线程,而直接返回失败,这样在用户下一次在点击下载的时候,就可以直接获取到文件了。

    开启异步线程(不阻塞线程)的方法

    1.使用Thread类

    2.使用ThreadPool线程池

    3.使用最新的Task

    第一种方法已经淘汰,因为这种方法是不会考虑机器的实际情况,会不停的创建线程,最终很容易导致内容溢出;

    第二种方法,在Task没有出现的时候经常使用,优点是线程池中会合理管理线程,如果到达上限后,后续创建的线程会进行排队,但是用它来操作线程略显麻烦

    第三种是新方法,比较推荐,改善了方法1和2的缺点。

    使用方法如下

    Task t1 = new Task(()=>{});
    t1.Start();

    或者

    Task.Run(()=> { });

    后者相当于将创建的线程直接启动了。

    后续执行ContinueWith

    可以对后台任务分成若干块,除了第一部分外,以ContinueWith连接,如下

     Task.Run(()=> { }).ContinueWith((t)=> { }).ContinueWith((t) => { });

    而参数t就是上一步执行的task,可以在ContinueWith方法对上一步的操作结果进行判断,以进行不同的处理

    Task的

    IsCompleted属性可以判断任务是否执行完成

    IsCompletedSuccessfully属性可以判断任务是否有异常

    可以放在ContinueWith中用来判断任务的执行情况

    线程同步

    Task对象使用Wait()方法来实现线程的等待,多个Task则可以使用Task.WaitAll()或者Task.WaitAny()来同步

    wait()和await

    为了线程同步有时候需要对线程进行等待,有两种方法,如

    Task.Run(()=>{}).Wait()

    或者

    await Task.Run(()=>{})

    这两种方法效果类似,都是将线程等待起来,有结果再继续,但是区别在于wait()是同步阻塞,而await是异步阻塞。

    也就是说wait()的时候,线程是占用状态,无法释放

    而await的时候,线程是释放的,可以用来做其他的工作

    一个现象

    经常发现一些朋友在写web项目代码的时候,方法中调用了很多await的异步接口,其实这些异步接口的使用并不能提高程序的性能,也就是说不是说一个接口使用同步接口调用了3秒,换成异步接口就变1秒了(去掉await并行执行另说)。

    执行效率还是不会变的,只不过程序在遇到await之后将线程释放,以提高网站的吞吐量。

    总结

    异步和多线程真的相当复杂,这里只是记录了自己使用中的一些经验,肯定有不足和错误的地方,希望见谅

    总之在使用异步和多线程的时候,要比单线程程序更加复杂,一些单线程程序中理所应当的东西,放在多线程异步环境下可能会出现大问题,使用的时候必须要小心和谨慎

  • 相关阅读:
    手机传感器大科普:手机中的陀螺仪、加速器和磁力计
    安卓新导入工程中gen目录下无R文件解决方法
    自写的 c# 锚点,前端显示 读书 记事本(一)
    update access 不能更新
    NHibenate初学资源推荐(切肤之痛)
    ASP.NET页面刷新和定时跳转
    c#(或vb.net)程序改进 (转载)
    感恩节的一天
    了解自己以及明白牛人会找什么样的人创业
    从别人如何读简历 看我们该如何成长
  • 原文地址:https://www.cnblogs.com/gamov/p/13215112.html
Copyright © 2020-2023  润新知