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

 

posted @ 2020-11-02 15:41  Youse的二分口粮地  阅读(130)  评论(0编辑  收藏  举报