zoukankan      html  css  js  c++  java
  • .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之后将线程释放,以提高网站的吞吐量。

    总结

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

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

  • 相关阅读:
    嵌入式操作系统-小型任务调度的理解(转)
    数据分析-pandas基础入门(一)
    硬件电路设计——低通滤波器的应用
    Docker
    AWK总结
    DNS解析
    TCP/IP
    Mysql优化部分总结
    Nginx配置文件释义备查
    时间模块
  • 原文地址:https://www.cnblogs.com/gamov/p/13215112.html
Copyright © 2011-2022 走看看