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

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

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. 什么是Unicode

    写这篇博客的原因, 从做软件开始,什么ASCII码, Unicode,UTF-8,UTF-16,UTF-32......这些鬼东西总是经常碰到,只知道这些鬼是编码格式,其他的就啥都不清楚了,既然总是遇 ...

  2. 【Alpha版本】冲刺阶段——Day2

    [Alpha版本]冲刺阶段--Day2 阅读目录 今日进展 问题困难 明日任务 今日贡献量 站立式会议 TODOlist [今日进展] 密码算法方面: 存储密码的步骤 使用CSPRNG生成一个长度足够 ...

  3. golang学习笔记16 beego orm 数据库操作

    golang学习笔记16 beego orm 数据库操作 beego ORM 是一个强大的 Go 语言 ORM 框架.她的灵感主要来自 Django ORM 和 SQLAlchemy. 目前该框架仍处 ...

  4. 【前端安全】JavaScript防流量劫持

    劫持产生的原因和方式 在网页开发的访问过程中,http是我们主要的访问协议.我们知道http是一种无状态的连接.即没有验证通讯双方的身份,也没有验证信息的完整性,所以很容易受到篡改.运营商就是利用了这 ...

  5. 三角形垂点坐标js算法(三点定圆求圆心)

    已知平面三点坐标A(x1, y1).B(x2, y2).C(x3, y3),三点定圆也就是三角形的中垂线交点, //平面三点定位算法 function locate(x1, y1, x2, y2, x ...

  6. 动态创建生成lambd表达式

    基于网上找的一段代码进行修改,目前扩展了NotContains方法的实现 using System; using System.Collections.Generic; using System.Co ...

  7. Porsche Piwis II V14. three hundred and fifty computer software Tester II

    Porsche piwis tester 2 Help Devices: SERP automatio tranny, air-conditioner, SRS, ABDOMINAL MUSCLES, ...

  8. SSMS登记密码清除

    如图,此界面的登录密码如果要清除,可以找到%AppData%\Microsoft\Microsoft SQL Server\100\Tools\Shell\SqlStudio.bin,将SqlStud ...

  9. orm操作

    一.必知必会13条 <1> all(): 查询所有结果 <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 <3> get(**kwar ...

  10. Python - mouse clicks and keystrokes on a background window

    https://stackoverflow.com/questions/43965437/python-mouse-clicks-and-keystrokes-on-a-background-wind ...