• 了解一些多线程相关的知识



    一、基础知识
    a)多线程的基础类为Thread,实际应用中一般用线程池,而不会直接用到Thread类。Thread基本的使用为:

    int i = 5;
    Thread thread = new Thread((p) => {
      Console.WriteLine(p);
    });
    thread.Start(i);

    可以用lambda写法,也可以指向一个方法,参数通过Start(i)来传递。
    b) 线程间的同步有几种方法
    可以在一个方法加上[MethodImpl(MethodImplOptions.Synchronized)],这样这个方法就无法被多个线程同时访问了,这属于方法粒度的控制。
    lock和Monitor可以提供代码块粒度的控制,用lock(<locker>){}或Monitor.Enter(<locker>)Monitor.Exit(<locker>)包围的代码块可以做到只允许一个线程同时访问。
    c) 对于单例模式,如果要保证线程安全,最好用这样的写法:

    class Singleton {
      private Singleton() { }
      private static object locker = new object();
      private static Singleton instance = null;

      public static Singleton GetSingleton() {
        if (instance == null) {
          lock (locker) {
            instance = new Singleton();
          }
        }
        return instance;
      }
    }

    需要注意的是,只有在instance==null的时候,才进行lock并初始化。

    d)线程的控制和线程池
    除了锁之外,还可以通过ManualResetEvent、AutoResetEvent来进行线程间的的通讯,以进行更精细的控制。基本的方法为WaitOne、Set、Reset

    AutoResetEvent are = new AutoResetEvent(false);
    Thread t1 = new Thread(() => {
      while (true) {
        Console.WriteLine("waitting open");
        are.WaitOne();
        Console.WriteLine("Open");
      }
    });


    在这里使用WaitOne就相当于为线程的流动加上了闸门,然后配合Set、Reset就可以控制线程的通断了。
    一般的场景推荐应用线程池。线程池中的线程使用完后不会被销毁,而是被回收,供下一次使用,这样可以节省反复创建、销毁线程造成的开销。线程池不追求精细化的控制,但能够提供简单的使用多线程的方式,自动进行性能调优,很适合于UI程序中避免程序假死。

    二、三种异步编程模型
    三种异步编程模型分别为EAP、APM、TPL,TPL方式使用最简洁。
    a) EAP(Event-based Asynchronous Pattern)方式使用简单,但不容易实现复杂逻辑,已不推荐使用。EAP使用回调的写法:

    private static void EAP() {
      WebClient wc = new WebClient();
      wc.DownloadStringCompleted += Wc_DownloadStringCompleted;
      wc.DownloadStringAsync(new Uri("http://www.github.com"));
      Console.WriteLine("Downloading");
    }
    private static void Wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) {
      Console.WriteLine(e.Result);
    }


    b) APM(Asynchronous Programming Model)方式也不推荐使用了,FileStream还保留有这种写法:

    private static void APM() {
      string filePath = "e:EFCore.txt";
      using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) {
        var buffer = new byte[128];
        var asyncState = new AsyncState { FS = fileStream, Buffer = buffer, EvtHandle = new ManualResetEvent(false) };
        IAsyncResult asyncResult = fileStream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(AsyncReadCallBack), asyncState);
        asyncState.EvtHandle.WaitOne();
        Console.WriteLine();
        Console.WriteLine("read complete");
        Console.ReadKey();
      }
    }

    public static void AsyncReadCallBack(IAsyncResult asyncResult) {
      var asyncState = (AsyncState)asyncResult.AsyncState;
      int readCn = asyncState.FS.EndRead(asyncResult);
      if (readCn > 0) {
        byte[] buffer;
        if (readCn == 128) {
          buffer = asyncState.Buffer;
        }
        else {
          buffer = new byte[readCn];
          Array.Copy(asyncState.Buffer, 0, buffer, 0, readCn);
        }
        string readContent = Encoding.UTF8.GetString(buffer);
        Console.Write(readContent);

        if (readCn < 128) {
          asyncState.EvtHandle.Set();
        }
        else {
          Array.Clear(asyncState.Buffer, 0, 128);
          asyncState.FS.BeginRead(asyncState.Buffer, 0, 128, new AsyncCallback(AsyncReadCallBack), asyncState);
        }
      }
    }


    c) TPL(Task Parallel Library)是在.Net4.0之后的新特性,异步实现起来更简洁、直观。比如FileStream的使用:

    async static void TPL() {
      string filePath = "e:/文章汇总/083.20170906 .Net Core(二)EFCore.txt";
      using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) {
        var buffer = new byte[128];
        var readLength = 0;
        while ((readLength = await fileStream.ReadAsync(buffer, 0, buffer.Length)) != 0) {
          string content = Encoding.UTF8.GetString(buffer);
          Console.WriteLine(content);
        }
        Console.WriteLine("complete");
      }
    }

    方法要被被async修饰,同时fileStream前使用await,然后就可以用很自然的的编码方式了。WinForm中的事件处理方法、MVC中的Action都可以使用这种方法。

    学习资料:如鹏网.net提高班http://www.rupeng.com/News/10/4603.shtml

  • 相关阅读:
    一个FLAG #03# 蛇形填数
    一个FLAG #02# 逆序输出
    一个FLAG #01# 重学C/C++以及算法
    MAVLink笔记 #01# 维基百科翻(译)
    编译原理 #04# 中缀表达式转化为四元式(JavaScript实现)
    Java开发:手机电话号码校验
    解决java poi循环遍历行getLastRowNum出现不准确的问题
    Redis的安装和简单测试
    JS解析xml字符串,并把xml展示在HTML页面上
    解决cxf+springmvc发布的webservice,缺少types,portType和message标签的问题
  • 原文地址:https://www.cnblogs.com/zhixin9001/p/7545545.html
Copyright © 2020-2023  润新知