提到多线程, 大家都知道, 在进程中启用多个线程进行工作, 会提升程序的效率等等。

本篇文章旨在解释多线程的基础概念之外, 还要结合实际的项目来谈多线程的具体使用。

Thread

我们知道启动一个线程最直观的方法就是使用Thread类,f12看一下这个类的构造函数, 不多如下图:

使用thread要用两个参数, 一个是ThreadStart, 一个是ParameterizedThreadStart。这俩的区别是一个可以带参数一个可以不带参数, 如下面代码:

class demo1
{
public void test()
{
ThreadStart threadStart = new ThreadStart(Calculate);
Thread thread = new Thread(threadStart);
thread.Start();
} public void Calculate()
{
double Diameter = 0.5;
Console.Write("The perimeter Of Circle with a Diameter of {0} is {1}", Diameter, Diameter * Math.PI);
}
} public void test
{
ParameterizedThreadStart threadStart=new ParameterizedThreadStart(Calculate);
Thread thread=new Thread();
thread.Start(0.9);
} public void Calculate(object arg)
{
double Diameter=double(arg);
Console.Write("The perimeter Of Circle with a Diameter of {0} is {1}",
Diameter,Diameter*Math.PI);
}

ps: 这两个例子来源于网上。

实际项目中很多都是需要传递参数的情况。可以将需要的参数和线程执行的方法放到一个类中去, 调用的时候声明一个类的实例, 然后初始化属性, 方法执行时直接使用类中初始化好的属性来执行, 比如下面这个例子:

public class MyThread
{
public double Diameter = 10;
public double Result = 0; public MyThread(int Diameter)
{
this.Diameter = Diameter;
} public void Calculate()
{
Console.WriteLine("Calculate Start");
Thread.Sleep(2000);
Result = Diameter * Math.PI; ;
Console.WriteLine("Calculate End, Diameter is {0},Result is {1}", this.Diameter, Result);
}
} MyThread t=new MyThread(5.0);
ThreadStart threadStart=new ThreadStart(t.Calculate)
Thread thread=new Thread(threadStart);
thread.Start();
}

Ps:在不想写类的时候可以写个匿名函数代替, 这里对匿名函数不做赘述了。可以参考匿名函数

要注意的是匿名方法过长会造成程序可读性降低。

但是项目需求更多的是需要传递参数而且需要从线程调用完方法完毕后返回执行结果等。如果是多个子线程, 那么这里面涉及到的技术问题是如何保证线程同步

线程池ThreadPool

线程池的使用是非常简单的,如下面的代码,把需要执行的代码提交到线程池,线程池内部会安排一个空闲的线程来执行你的代码,完全不用管理内部是如何进行线程调度的。

ThreadPool.QueqeUserWorkItem(t=>Console.WriteLine("Hello thread pool"));

每个CLR都有一个线程池,线程池在CLR内可以多个AppDomain共享,线程池是CLR内部管理的一个线程集合,初始是没有线程的,在需要的时候才会创建。线程池的主要结构图如下,基本流程如下:

1.线程池内部维护一个请求列队,用于缓存用户请求需要执行的代码任务,就是Thread.QueqeUserWorkItem提交的请求;

2.有新任务后,线程池使用空闲线程或者新线程来执行队列请求;

3.任务执行完后线程不会销毁,留着重复使用;

4.线程池自己负责维护线程的创建和销毁,但线程池有大量闲置的线程是,线程池会自动结束一部分多余的线程来释放资源;

线程池是有一个容量的,因为他是一个池子吗,可以设置线程池的最大活跃线程数,调用方法Threadpool.SetMaxThreads可是设置相关参数,但很多线程实践里都不建议程序猿们自己去设置这些参数,其实微软为了提高线程池性能,做了大量的优化,线程池可以很智能的确定是否要创建或者消费线程,大多数情况都可以满足需求了。线程池使得线程可以充分有效的被利用,减少了任务启动的延迟,也不用大量的去创建线程,避免了大量线程的创建和销毁对性能造成极大影响。

上面了解了线程的基本原理和诸多优点后,如果你是一个爱思考的猿类,应该会很容易的发现很多疑问,比如把任务添加到线程池队列后,怎么取消和挂起呢?如何知道他执行完了呢,下面来总结一下线程池的不足:

1.线程池内的线程不支持线程的挂起、取消等操作,如想要取消线程池的任务,.net支持一种协作方式取消,使用起来也不少很方便,而且有些场景并不是很满足需求;

2.线程内的任务没有返回值,也不知道何时执行完成;

3.不支持设置线程的优先级,还包括其他类似需要对线程有更多的控制的需求也不支持;

因此微软为我们提供了另外一个东西叫做Task来补充线程池的某些不足。

任务Task与并行Parallel

任务Task与并行Parallel本质上内部都是使用的线程池,提供了更丰富的并行编程的方式。任务Task基于线程池,可支持返回值,支持比较强大的任务执行计划定制等功能,下面实例。Task提供了很多方法和属性,通过这些方法和属性能够对Task的执行进行控制,并且能够获得其状态信息。Task的创建和执行都是独立的,因此可以对关联操作的执行拥有完全的控制权。

待续....

//创建一个任务
Task<int> t1 = new Task<int>(n =>
{
System.Threading.Thread.Sleep(1000);
return (int)n;
}, 1000);
//定制一个延续任务计划
t1.ContinueWith(task =>
{
Console.WriteLine("end" + t1.Result);
}, TaskContinuationOptions.AttachedToParent);
t1.Start();
//使用Task.Factory创建并启动一个任务
var t2 = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
Console.WriteLine("t1:" + t1.Status);
});
Task.WaitAll();
Console.WriteLine(t1.Result);

并行Parallel内部其实使用的是Task对象(TPL会在内部创建Task的实例),所以的并行任务完成后才会返回。少量短时间任务建议就不要使用并行Parallel了,并行Parallel本身也是有性能开销的,而且还要进行并行任务调度、创建调用方法的委托等。

【.Net】结合项目谈谈多线程的更多相关文章

  1. Java实验项目四——多线程矩阵相乘算法的设计

    Program:多线程矩阵相乘算法的设计 Description:利用多线程实现矩阵相乘,因为各个线程的运算互不影响, 所以不用使用锁,代码如下: thread.OperateMatrix类,实现矩阵 ...

  2. 开源项目实现多线程下载 (xutils)

    public void download(View v){         EditText et_url = (EditText) findViewById(R.id.et_url);        ...

  3. JAVA必背面试题和项目面试通关要点

    一 数据库 1.常问数据库查询.修改(SQL查询包含筛选查询.聚合查询和链接查询和优化问题,手写SQL语句,例如四个球队比赛,用SQL显示所有比赛组合:举例2:选择重复项,然后去掉重复项:) 数据库里 ...

  4. JAVA JAVA面试题和项目面试核心要点精华总结(想进大公司必看)

    http://blog.csdn.net/ourpush/article/details/53706524 1.常问数据库查询.修改(SQL查询包含筛选查询.聚合查询和链接查询和优化问题,手写SQL语 ...

  5. JAVA必背面试题和项目面试通关要点(带答案)

    转载:https://blog.csdn.net/qq_36896779/article/details/78247050 一 数据库 1.常问数据库查询.修改(SQL查询包含筛选查询.聚合查询和链接 ...

  6. day9面向对象,多线程2

    一.获取全部qq成员头像 import os,requests,pymongo class Qqgroup(object):#定义一个类 #定义获取QQ群的请求rul,抓包获取 group_rul = ...

  7. 多线程系列之 Java多线程的个人理解(一)

    前言:多线程常常是程序员面试时会被问到的问题之一,也会被面试官用来衡量应聘者的编程思维和能力的重要参考指标:无论是在工作中还是在应对面试时,多线程都是一个绕不过去的话题.本文重点围绕多线程,借助Jav ...

  8. Java复习8.多线程

    Java复习8 多线程知识 20131007 前言: 在Java中本身就是支持多线程程序的,而不是像C++那样,对于多线程的程序,需要调用操作系统的API 接口去实现多线程的程序,而Java是支持多线 ...

  9. iOS技术面试01:多线程与网络

    1. 多线程的底层实现? 1> 首先搞清楚什么是线程.什么是多线程.多线程的使用场合(线程有时被称为轻量级进程,是程序执行流的最小单元.多线程是指软件或者硬件实现多个线程并发执行的技术.多线程的 ...

随机推荐

  1. 20155228 2016-2017-2 《Java程序设计》第2周学习总结

    20155228 2006-2007-2 <Java程序设计>第2周学习总结 教材学习内容总结 类型 Java可以区分为基本类型和类类型(或称参考类型).对于基本类型,使用时得考虑一下数据 ...

  2. flask 重定向到上一个页面,referrer、next参数

    重定向会上一个页面 在某些场景下,我们需要在用户访问某个url后重定向会上一个页面,比如用户点击某个需要登录才能访问的连接,这时程序会重定向到登录页面,当用户登录后比较合理的行为是重定向到用户登录前浏 ...

  3. 【Alpha版本】冲刺阶段——Day5

    [Alpha版本]冲刺阶段--Day5 阅读目录 今日进展 问题困难 明日任务 今日贡献量 站立式会议 TODOlist [今日进展] 完成登录类代码 public void LOGIN() { co ...

  4. 什么是FEBS

    FEBS后台权限管理系统      FEBS是一个简单高效的后台权限管理系统.项目基础框架采用全新的Java Web开发框架 —— Spring Boot2.0.4,消除了繁杂的XML配置,使得二次开 ...

  5. SpringBoot整合redis哨兵主从服务

    前提环境: 主从配置 http://www.cnblogs.com/zwcry/p/9046207.html 哨兵配置 https://www.cnblogs.com/zwcry/p/9134721. ...

  6. AtCoder Regular Contest 077 C - pushpush

    题目链接:http://arc077.contest.atcoder.jp/tasks/arc077_a Time limit : 2sec / Memory limit : 256MB Score ...

  7. centos 文件新建、删除、移动、复制等命令

    创建目录 mkdir 文件名 mkdir /var/www/test cp复制命令 cp命令复制文件从一个位置到另一位置.如果目的地文件存在,将覆复写该文件: 如果目的地目录存在,文件将复制到该目录下 ...

  8. watch解放你的双手

    有时候我们需要重复执行某个命令,观察某个文件和某个结果的变化情况.可以写脚本去实现这些需求,但是有更简单的方法,本文档要介绍的就是watch命令. 1. 以固定时间反复执行某个命令 root@jaki ...

  9. OpenCV入门笔记(七) 文字区域的提取

    https://blog.csdn.net/huobanjishijian/article/details/63685503 前面我们已经学了一些OpenCV中基本的图片处理的知识,可以拿来做一些小应 ...

  10. 获取其他线程的数据用 queue, 多进程Q

    获取其他线程的数据用 queue, 多进程Q