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

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

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. crm

    CRM 开发 需求分析 存储所有的客户咨询信息 避免重复数据 客户的多次跟踪记录 客户来源.成单率分析 每个销售只能修改自己的客户信息 报名流程开发 班级管理 学员成绩,出勤管理 问卷调查 校区管理 ...

  2. codeforces 979C Kuro and Walking Route

    题意: 给出一棵树,其中有两个点,x和y,限制走了x之后的路径上不能有y,问可以走的路径(u,v)有多少条,(u,v)和(v,u)考虑为两条不同的路径. 思路: 简单树形dp,dfs统计在x到y路径( ...

  3. 【CDH学习之三】CDH安装

    登录CM 1.版本选择 免费版本的CM5已经去除50个节点数量的限制. 各个Agent节点正常启动后,可以在当前管理的主机列表中看到对应的节点. 选择要安装的节点,点继续. 接下来,出现以下包名,说明 ...

  4. GDB && QString

    [1]GDB && QString GDB的print命令仅能打印基本数据类型,而像QString这样的复杂类型就无能为力了! 如果调试时不能看QString的值,很让人抓狂!!!幸好 ...

  5. c# 设置控件的前景颜色和背景颜色

    AutoSize:设置为false取消自动计算尺寸功能,控件的大小则按照设定的Size来呈现,设置为true自动计算大小 TextAlign:设置对齐方式 // // 摘要: // 用默认的所有者运行 ...

  6. 微信小程序制作家庭记账本之五

    第五天,开发进度没有进行,不知道该如何下手完成小程序的开发.

  7. Linux基础命令---显示路由表route

    route route指令用于显示或者修改IP路由表.它的主要用途是在使用ifconfig(8)程序配置接口后,通过接口设置到特定主机或网络的静态路由.当使用add或del选项时,路由将修改路由表.如 ...

  8. Linux服务器---流量监控MRTG

    MRTG MRTG可以分析网络流量,但是它必须依赖SNMP协议.将收集到的数据生成HTML文件,以图片的形式展示出来 1.安装一些依赖软件 [root@localhost bandwidthd-2.0 ...

  9. Linux centos7 下 svn 服务器搭建

    摘自:https://www.cnblogs.com/mymelon/p/5483215.html 鉴于在搭建时,参考网上很多资料,网上资料在有用的同时,也坑了很多人 本文的目的,也就是想让后继之人在 ...

  10. MySQL半同步安装以及参数

    MySQL半同步安装以及参数 基于MySQL5.5 官档地址: Semisynchronous Replication Administrative Interface https://dev.mys ...