• C#多线程


    背景

      web开发本来就是异步多线程,好学一些。C#不一样,做工具的时候,数据量过大会出现假死,所以考虑多线程。

    学习笔记

    1.C#多线程编程

    2.C#多线程、并行和异步编程学习笔记

    2020.11.13

    Simple Threading 

    Threading in .NET and WinForms

    委托:包含方法数组的数据类型。委托中的所有方法应具有相同的签名和相同的返回类型。委托的声明本身将定义委托的方法签名和返回类型。

    public delegate void MyDelegate(int arg);

    2020.11.16

    1.1 Threading

    1.1.2 Threading in .NET

     要将函数添加到委托中,请创建委托的实例,然后将函数名称作为参数传递。 

    MyDelegate delInstance = new MyDelegate(Function1);

    多播:  

    delInstance += new MyDelegate(Function2);

    1.1.3 Creating Threads in .NET

      创建线程: 

     1  class Test0
     2     {
     3         public static void Main()
     4         {
     5             Thread t = new Thread(new ThreadStart(Test0.MyFunction));
     6             t.Start();
     7             for (int i = 0; i < 100; i++)
     8                 Console.WriteLine("I am in Main Thread {0}", i);
     9         }
    10 
    11         public static void MyFunction()
    12         {
    13             for (int i = 0; i < 100; i++)
    14                 Console.WriteLine("I am in Different Thread {0}", i);
    15         }
    16     }
    View Code

      委托具有由编译器提供的名为BeginInvoke()的内置函数。此函数可用于在线程中执行函数。任何委托上的BeginInvoke调用都将在单独的线程中执行。

       在下面的代码中,对委托实例的BeginInvoke调用在单独的线程中运行MyFunction。下面代码的输出将是控制台消息在主线程和委托线程之间交换(类似于使用Thread类)。请注意,无法通过BeginInvoke多播委托。

     1 class Test1
     2     {
     3         public delegate void MyDelegate(int i, string str);
     4         public static void Main()
     5         {
     6             MyDelegate delInstance = new MyDelegate(MyFunction);
     7             delInstance.BeginInvoke(100, " I am in Delegate Thread", null, null);
     8             for (int i = 0; i < 100; i++)
     9                 Console.WriteLine("I am in Main Thread {0}", i);
    10             Console.ReadKey();
    11         }
    12         public static void MyFunction(int count, string str)
    13         {
    14             for (int i = 0; i < count; i++)
    15                 Console.WriteLine(str + " {0}", i);
    16         }
    17     }
    View Code

      由于BeginInvoke是异步调用(仅触发另一个线程并继续运行下一行,而不等待完成另一个线程),因此它无法直接获取函数调用的返回值。因此,我们需要某种机制来收集返回值。 C#中BeginInvoke函数的实现返回IAsyncResult类型。必要时,此IAsyncResult可用于获取返回值。有一个名为EndInvoke的函数,它将此IAsynResult作为参数并收集返回值。因此,可以使用EndInvoke函数来收集返回值。

     1    class Test2
     2     {
     3         public delegate bool MyDelegate(int i, string str);
     4         public static void Main()
     5         {
     6             MyDelegate delInstance = new MyDelegate(MyFunction);
     7             IAsyncResult ref1 = delInstance.BeginInvoke(100, "I am in Delegate Thread", null, null);
     8             for (int i = 0; i < 100; i++)
     9                 Console.WriteLine("I am in Main Thread {0}", i);
    10             bool status = delInstance.EndInvoke(ref1);
    11             Console.ReadKey();
    12         }
    13         public static bool MyFunction(int count, string str)
    14         {
    15             for (int i = 0; i < count; i++)
    16                 Console.WriteLine(str + " {0}", i);
    17             return true;
    18         }
    19     }
    View Code

      在下面的代码中,对EndInvoke的调用将阻塞主线程,直到MyFunction完成。
    如果线程已经完成执行,则对EndInvoke的调用将立即收集返回值。否则,它将等待线程完成并获得结果。
    在调用BeginInvoke时,我们尚未创建任何线程,那么谁在创建线程?它如何在单独的线程中运行?
    要回答这些问题,首先让我们知道什么是线程池。

     1  class Test4
     2     {
     3         public delegate int MyDelegate(int i, string str);
     4         public static void Main()
     5         {
     6             MyDelegate delInstance = new MyDelegate(MyFunction);
     7             IAsyncResult iRef = delInstance.BeginInvoke(100, " I am in Delegate Thread",
     8                                                       null, null);
     9             int val = delInstance.EndInvoke(iRef);
    10             Console.ReadKey();
    11         }
    12         public static int MyFunction(int count, string str)
    13         {
    14             int i;
    15             for (i = 0; i < count; i++)
    16                 Console.WriteLine(str + " {0}", i);
    17             return i;
    18         }
    19     }
    View Code

    1.1.4 Thread Pool

      在运行时创建线程并非易事。对于较小的线程,大多数时间将花费在创建线程上,而不是在线程上执行功能。
    CLR(公共语言运行时)在池中已经创建了一些线程,以便可以在需要时使用它们。这些线程称为线程池线程。如果我们在线程池中使用线程,则在线程完成时,该线程将不会被销毁。线程将在挂起状态下返回线程池。该挂起的线程可以重新用于其他目的。
    BeginInvoke函数使用这些线程池线程来执行功能。使用线程池线程可以节省线程创建时间。 

    1.2 Threading in WinForms

    1.2.1 WinForms Internals

    1  private void Form1_Load(object sender, EventArgs e)
    2         {
    3             AddControl();
    4         }
    5         void AddControl()
    6         {
    7             TextBox testBox1 = new TextBox();
    8             Controls.Add(testBox1);
    9         }
    View Code

    1.2.2 Control.Invoke

     1   public delegate void MyDelegate();
     2 
     3         private void Form1_Load(object sender, EventArgs e)
     4         {
     5 
     6             Thread t = new Thread(new ThreadStart(RunInThread));
     7             t.Start();
     8         }
     9         void RunInThread()
    10         {
    11             MyDelegate delInstatnce = new MyDelegate(AddControl);
    12             this.Invoke(delInstatnce);
    13             MessageBox.Show("Hello");
    14             //Add your code that needs to be executed in separate thread 
    15             //except UI updation
    16         }
    17         void AddControl()
    18         {
    19             TextBox textBox1 = new TextBox();
    20             Controls.Add(textBox1);
    21         }
    22     }
    View Code

    1.2.3 Control.BeginInvoke

      如前所述,Control类上的BeginInvoke方法将调用放置在发布消息队列中。该调用最终将由主线程执行,并且BeginInvoke方法不会像Invoke那样阻塞当前线程。将呼叫放在帖子消息队列中后,它将开始执行下一行。可以使用EndInvoke方法收集返回值。

     1   public delegate void MyDelegate();
     2 
     3         private void Form1_Load(object sender, EventArgs e)
     4         {
     5             Thread t = new Thread(new ThreadStart(RunInThread));
     6             t.Start();
     7         }
     8         void RunInThread()
     9         {
    10             MyDelegate delInstatnce = new MyDelegate(AddControl);
    11             this.BeginInvoke(delInstatnce);
    12             MessageBox.Show("Hello");
    13             //Add your code that needs to be executed in separate thread 
    14             //except UI updation
    15         }
    16         void AddControl()
    17         {
    18             TextBox textBox1 = new TextBox();
    19             Controls.Add(textBox1);
    20             Thread.Sleep(10000);
    21         }
    View Code

    1.2.4 Control.InvokeRequired

     1  delegate void AddForm();
     2 
     3         private void Form1_Load(object sender, EventArgs e)
     4         {
     5 
     6             Thread t = new Thread(new ThreadStart(RunInThread));
     7             t.Start();
     8         }
     9         void RunInThread()
    10         {
    11             AddControl();
    12         }
    13         void AddControl()
    14         {
    15             if (this.InvokeRequired)
    16             { //如果当前线程不是主线程,则返回true;如果当前线程是主线程,则返回false。
    17                 //因此,UI的任何更新都应通过InvokeRequired属性进行,这是一种安全的编码做法。
    18                 //调用者将不会处理Invoke方法,而是会在函数内部实现。
    19                 AddForm add = new AddForm(AddControl);
    20                 this.Invoke(add);
    21             }
    22             else
    23             {
    24                 TextBox testBox1 = new TextBox();
    25                 Controls.Add(testBox1);
    26             }
    27 
    28         }
    View Code
  • 相关阅读:
    Oracle SQL Developer 编辑区不能删除,后退,空格,复制粘贴等功能都失效的解决办法
    oracle的 分表 详解 -----表分区
    【Spring框架】<mvc:default-servlet-handler/>的作用
    git revert
    log4j:ERROR A "org.apache.log4j.DailyRollingFileAppender" object is not assignable to a "org.apache.log4j.Appender" variable.
    [已解决] java 增加 ALPN支持
    [已解决] 快速理解RSA算法
    [已解决] C3p0连接配置
    [已解决] git 重命名文件夹
    [已解决] No syntax specified for the proto file : xxx.proto
  • 原文地址:https://www.cnblogs.com/youzi-xuchongyou/p/13914783.html
Copyright © 2020-2023  润新知