一 什么是多线程

1、 什么是进程?一个 exe 运行一次就会产生一个进程,一个 exe 的多个进程之 间数据互相隔离。

2、 一个进程里至少有一个线程:主线程。我们平时写的控制台程序默认就是单线程的,代 码从上往下执行,一行执行完了再执行下一行;

3、 什么是多线程:一个人两件事情同时做效率高。同一时刻一 个人只能干一件事情,其实是在“快速频繁切换”,如果处理不当可能比不用多线程效率还低

二  Thread 对象

2.1 thread基础写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public static void ThreadTest()
        {
            int a = 0;
            Thread thread1 = new Thread(m=>
            {
                for (int i = 0; i < 20; i++)
                {
                    a = a + 1;
                    Console.WriteLine("线程1:"+ a);
                }
 
            });
 
            Thread thread2 = new Thread(m =>
            {
            for (int i = 0; i < 20; i++)
            {
                    a = a + 1;
                Console.WriteLine("线程2:"+ a);
                }
 
            });
             
            thread1.Start();
            thread2.Start();
            Console.ReadKey();
        }

这段代码输出结果如下:

可以看出两个子线程启动后是并行执行的,所以输出结果没有按照顺序来

2.2 设置线程的优先级

thread1.Priority=ThreadPriority。。。

2.3  t1.Join()当前线程等待 t1 线程执行结束,实例如下:

这段代码执行过后输出的结果就是正常的从1输出到了40

public static void ThreadTest()
{
int a = 0;
Thread thread1 = new Thread(m=>
{
for (int i = 0; i < 20; i++)
{
a = a + 1;
Console.WriteLine("线程1:"+ a);
} }); Thread thread2 = new Thread(m =>
{
//等待thread1线程任务完成后在执行
thread1.Join();
for (int i = 0; i < 20; i++)
{
a = a + 1;
Console.WriteLine("线程2:"+ a);
} });
//可以将参数传入到子线程中
thread1.Start(a);
//thread1.Join(); 或者将Join放在这里
thread2.Start(a);
Console.ReadKey(); }

2.4 Interrupt方法

Interrupt 用于提前唤醒一个在 Sleep 的线程,Sleep 方法会抛出 ThreadInterruptedException 异常 代码如下:

代码输出到9的时候线程会休眠8秒钟,但是运行到主线程thread1.Interrupt()时,子线程会被唤醒,然后执行catch里面的Console.WriteLine("线程被唤醒");之后接着从10开始输出到2000。需要注意的是只有线程自身能让自身休眠

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static void ThreadTest2()
        {
            Thread thread1 = new Thread(() =>
            {
                for (int i = 0; i < 2000; i++)
                {
                    if (i==10)
                    {
                        //唤醒线程之后会引发ThreadInterruptedException类型的异常,所以需要try catch
                        try
                        {
                            //子线程休眠8秒钟
                            Thread.Sleep(8000);
                        }
                        catch (ThreadInterruptedException ex)
                        {
                            Console.WriteLine("线程被唤醒");
                        }
                    }
                    Console.WriteLine(i);
                }
            });
            thread1.Start();
            //提前唤醒在沉睡的子线程
            Thread.Sleep(3000);
            thread1.Interrupt();
            Console.ReadKey();
        }

  

三 线程池

3.1、线程池:因为每次创建线程、销毁线程都比较消耗 cpu 资源,因此可以通过线程池进行 优化。线程池是一组已经创建好的线程,随用随取,用完了不是销毁线程,然后放到线程池 中,供其他人用。

3.2、用线程池之后就无法对线程进行精细化的控制了(线程启停、优先级控制等)

3.3、ThreadPool 类的一个重要方法:

  static bool QueueUserWorkItem(WaitCallback callBack)

  static bool QueueUserWorkItem(WaitCallback callBack, object state)

3.4、除非要对线程进行精细化的控制,否则建议使用线程池,因为又简单、性能调优又更好。

1
2
3
4
5
6
7
8
9
10
11
12
13
//QueueUserWorkItem是一个静态方法不需要New
public static void ThreadPool()
{
    System.Threading.ThreadPool.QueueUserWorkItem(m=>
    {
        for (int i = 0; i < 1000; i++)
        {
            i++;
            Console.WriteLine(i);
        }
    });
    Console.ReadKey();
}

  

四 TPL风格的异步方法

TPL(Task Parallel Library)是.Net 4.0 之后带来的新特性,更简洁,更方便。现在在.Net 平台下已经大面积使用。

注意方法中如果有 await,则方法必须标记为 async,不是所有方法都可以被轻松的标记 为 async。WinForm 中的事件处理方法都可以标记为 async、MVC 中的 Action 方法也可以标 记为 async、控制台的 Main 方法不能标记为 async。  TPL 的特点是:方法都以 XXXAsync 结尾,返回值类型是泛型的 Task<T>。  TPL 让我们可以用线性的方式去编写异步程序,不再需要像 EAP 中那样搞一堆回调、逻 辑跳来跳去了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/TPL风格返回的Task<T> 泛型的数据
//await 关键字等待异步方法返回
public static async void Task()
{
    WebClient wc = new WebClient();
    string s= await wc.DownloadStringTaskAsync("http://www.baidu.com");
    Console.WriteLine(s);
    Console.ReadKey();
}
public static void Task2()
{
    WebClient wc = new WebClient();
    //若果不使用await关键字就得使用Task<string>类型来接收数据
    Task<string> s2 = wc.DownloadStringTaskAsync("http://www.baidu.com");
    Console.ReadKey();
}

  

自己编写一个TPL风格的异步方法:

使用了async关键字就必须返回Task泛型数据类型的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static Task<string> StringAsync()
{
   return Task.Run(() =>
    {
        Thread.Sleep(5000);
        return "hehe";
    });
           
}
// GET: Home
public async Task<ViewResult> Index()
{
 
    var s = await StringAsync();
    return View();
}

  

如果返回值就是一个立即可以随手可得的值,那么就用 Task.FromResult()  如果是一个需要休息一会的任务(比如下载失败则过 5 秒钟后重试。主线程不休息,和 Thread.Sleep 不一样),那么就用 Task.Delay()。 3、Task.Factory.FromAsync()把 IAsyncResult 转换为 Task,这样 APM 风格的 api 也可以用 await 来调 用。 4、编写异步方法的简化写法。如果方法声明为 async,那么可以直接 return 具体的值,不再用创建 Task,由编译器创建 Task:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static async Task<int> F1Async()
{
     return 1;
 }
  
static Task<int> F2Async()
     return Task.FromResult(3);
}
  
static Task<int> F3Async()
     return Task.Run(()=> { 
     return 1 + 3;  });
}

一定要让 async 的传染性(调用异步方法要用 await,用了 await 方法就要声明为 async,调 用我这个 async 方法的地方必须要 await……)不要轻易直接调用 Task 的 Wait、WaitAll 等方 法。等待一个用 await,而不是 task.Wait();等待多个用 await Task.WhenAll(),而不是 Task.WaitAll()

 
 

c#多线程介绍1的更多相关文章

  1. Java 并发和多线程(一) Java并发性和多线程介绍[转]

    作者:Jakob Jenkov 译者:Simon-SZ  校对:方腾飞 http://tutorials.jenkov.com/java-concurrency/index.html 在过去单CPU时 ...

  2. Java并发性和多线程介绍

    java并发性和多线程介绍: 单个程序内运行多个线程,多任务并发运行 多线程优点: 高效运行,多组件并行.读->操作->写: 程序设计的简单性,遇到多问题,多开线程就好: 快速响应,异步式 ...

  3. C#多线程介绍(下)

    转载原文:这里是链接内容 转载原文:这里写链接内容 转载原文:这里写链接内容 (重要事情说三遍) 引言 本文主要从线程的基础用法,CLR线程池当中工作者线程与I/O线程的开发,并行操作PLINQ等多个 ...

  4. c#多线程介绍(上)

    转载原文:这里是链接内容 转载原文:这里写链接内容 转载原文:这里写链接内容 (重要事情说三遍) 引言 本文主要从线程的基础用法,CLR线程池当中工作者线程与I/O线程的开发,并行操作PLINQ等多个 ...

  5. iOS边练边学--多线程介绍、NSThread的简单实用、线程安全以及线程之间的通信

    一.iOS中的多线程 多线程的原理(之前多线程这块没好好学,之前对多线程的理解也是错误的,这里更正,好好学习这块) iOS中多线程的实现方案有以下几种 二.NSThread线程类的简单实用(直接上代码 ...

  6. Java Thread 多线程 介绍

    1.线程概述 几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程. 当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程. 2.线程 ...

  7. iOS开发——多线程篇——多线程介绍

    一.进程和线程1.什么是进程进程是指在系统中正在运行的一个应用程序每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开迅雷.Xcode,系统就会分别启动2个进程 通过“活动监 ...

  8. iOS多线程介绍

    一.线程概述 有些程序是一条直线,起点到终点:有些程序是一个圆,不断循环,直到将它切断.直线的如简单的Hello World,运行打印完,它的生命周期便结束了,像昙花一现那样:圆如操作系统,一直运行直 ...

  9. python-进程之间通信、多线程介绍

    一.进程之间通信 进程的任务有三种状态:运行,就绪,阻塞. 加锁可以让多个进程修改同一块数据时,同一时间只能由一个任务可以进行修改,即串行的修改.牺牲了速度,保证了数据安全. 虽然可以使用文件共享数据 ...

随机推荐

  1. Vue 父组件循环使用refs调用子组件方法出现undefined的问题

    Vue 父组件循环使用refs调用子组件方法出现undefined的问题 1. 背景 最近前端项目遇到一个问题,我在父组件中使用了两个相同的子组件child,分别设置ref为add和update.其中 ...

  2. script 加载顺序问题的延展研究

    今天群里有人问为什么会出现脚本的加载顺序与定义脚本顺序不一致的问题,这个问题引起了我的好奇,经过一番调研,有了这篇文章. 这是一个伪命题吗? 首先,W3C 推荐 script 脚本应该被立即加载和执行 ...

  3. 伪类:after的使用以及结合attr来添加属性的技巧

    本案例以实现侧边栏的效果为例来说明 直接上代码看效果: css <style type="text/css"> *{;;list-style: none;} ul{;t ...

  4. 字典重复key的合并

    from collections import defaultdict d=defaultdict(set) s=[("001","A"),("001 ...

  5. Selenium 对窗口对HTML的操作举例

  6. 软件测试实习生 带人计划 Plan for Training Inten

    临时拟了个提纲,以后慢慢补充吧 序号 培训内容 时间安排 1 根据项目需求,编写测试用例,针对存储过程 2 存储过程的走读,以及怎样执行测试用例和查看结果 3 根据项目需求,编写测试用例,针对接口[C ...

  7. 使用 apply 函数族

    之前,我们讨论过可以使用 for 循环,在一个向量或列表上进行迭代,重复执行某个表达式.但是在实践中,for 循环往往是最后的选择,因为每次迭代都是相互独立的,所以我们可以使用更简洁更方便的读写方式来 ...

  8. Python - configParser模块学习

    configParser 模块用于操作配置文件 注:Parser汉译为“解析”之意. 配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),每个节可以有多个参数(键= ...

  9. C#中的?

    1. 可空类型修饰符(?):引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; 是正确的,int i=null; 编译器就会报错.为了使值类型也 ...

  10. vsftpd配置手册(实用)

    作者: 木頭    来源: PHPChina 开源社区门户1.vsftpd配置参数详细整理 #接受匿名用户 anonymous_enable=YES #匿名用户login时不询问口令 no_anon_ ...