首页 > 编程语言 >(29)C#多线程

(29)C#多线程

时间:2022-12-08 19:01:46浏览次数:65  
标签:Task Console Thread C# void 29 static WriteLine 多线程

使用线程的原因

1.不希望用户界面停止响应。

2.所有需要等待的操作,如文件、数据库或网络访问需要一定的时间。

一个进程的多个线程可以同时运行不同cpu或多核cpu的不同内核上

注意多线程访问相同的数据必须实现同步机制

 

编写能够利用并行性的代码需要区分两种场景:任务并行性和数据并行性

任务并行性:使用CPU的代码被并行化,利用cpu的多个核心快速的完成包含多个任务的活动。

数据并行性:使用了数据集合,在集合上执行的工作被划分为多个任务。

任务并行性和数据并行性可以混合起来。

 

Parallel类(自 4.0 起可用)

Parallel类定义了并行的for和foreach的静态方法,使用多线程来完成作业。

Parallel.For()和Parallel.ForEach()方法再每次迭代中调用相同的代码。而Parallel.Invoke()方法允许同时调用不同的方法。

Parallel.Invoke()用于任务并行性,Parallel.Invoke()用于数据并行性。

 

Parallel.For()

 

using System.Threading;
using System.Threading.Tasks;

 

class Program
{
static void Main(string[] args)
{

//参数1 int ,参数2 int,参数3 action<int>
Parallel.For(3, 10, (i)=> {
Console.WriteLine("id:" + i + " thread:" + Thread.CurrentThread.ManagedThreadId);
});
Console.WriteLine("end");
Console.ReadLine();
}
}

 

参数3的action中可以添加一个控制状态的类型

​Action<Int32,ParallelLoopState>)​

使用 Break()和Stop()尽早的结束循环,在结束前启动的线程仍可以继续执行。

Break() 尽早结束当前以外的线程

Stop() 尽早结束

class Program
{
static void Main(string[] args)
{

Parallel.For(3, 100000, (i, state) => {
if (i > 6)
{
state.Stop();
Console.WriteLine("abc");
}
Console.WriteLine("id:" + i + " thread:" + Thread.CurrentThread.ManagedThreadId);
});
Console.WriteLine("end");
Console.ReadLine();
}
}

 

Parallel.ForEach()

用来遍历一个能被迭代的集合,相当于一个多线程的foreach版

class Program
{
static void Main(string[] args)
{
int[] count = { 2, 3, 6, 4, 7, 25, 42, 612, 12 };
Parallel.ForEach(count, (i, state) => {

Console.WriteLine("id:" + i + " thread:" + Thread.CurrentThread.ManagedThreadId);
});
Console.WriteLine("end");
Console.ReadLine();
}
}

 

Parallel类返回类型

Parallel.for 和 Parallel.foreach 返回 ParallelLoopResult 类型,用来判断是否执行完成
class Program
{
static void Main(string[] args)
{
ParallelLoopResult res = Parallel.For(3, 10, (i, state) => {
Console.WriteLine("id:" + i + " thread:" + Thread.CurrentThread.ManagedThreadId);
});
Console.WriteLine(res.IsCompleted);
Console.ReadLine();
}
}

 

 

 

Parallel.Invoke()

public static void Invoke (params Action[] actions) ,可以调用多个不同的方法

 

class Program
{
static void Main(string[] args)
{
Parallel.Invoke(a,b);
Console.WriteLine("end");
Console.ReadLine();
}

static public void a()
{
Console.WriteLine("a");
}
static public void b()
{
Console.WriteLine("b");
}
}

 

 任务

 

 1.工厂类的方式启动一个线程

static void Main(string[] args)
{
var tf = new TaskFactory();
Task task = tf.StartNew(abc);
Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}

static public void abc()
{
Console.WriteLine("abc:"+ Thread.CurrentThread.ManagedThreadId);
}

 

 

(29)C#多线程_数据

 

2.Task的静态Factory属性启动线程

 

static void Main(string[] args)
{

Task task = Task.Factory.StartNew(abc);
Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}

 

3.使用Task的构造函数

 实例化后不会立即启动线程,当对象调用Start()方法时才开始启动

static void Main(string[] args)
{

Task task =new Task(abc);
task.Start();
Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}

 

 4.使用Task的静态Run方法

static void Main(string[] args)
{
Task task =Task.Run(abc);
Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}

 

5.使用Task同步运行

static void Main(string[] args)
{
Task task =new Task(abc);
task.RunSynchronously();
Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}

 

6.使用单独的线程,而不是线程池

static void Main(string[] args)
{
Task task =new Task(abc,TaskCreationOptions.LongRunning);
task.Start();
Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}

 

7.带返回值的任务

  Func<>   返回​​Task<TResult>​

static void Main(string[] args)
{
Task<int> task =Task<int>.Run(()=>{
Console.WriteLine("111");
return 5;
});
Console.WriteLine(task.Result);
Console.WriteLine("abc");
Console.ReadLine();
}

task.Result会等到Task执行完才会被调用相当于调用的wait,所以abc会在结果打印之后再打印

 

8.连续的任务

 ContinueWith

static void Main(string[] args)
{
Task task1 = new Task(a);
Task task2 = task1.ContinueWith(b);
Task task3 = task2.ContinueWith(c);
task1.Start();
Console.WriteLine("end");
Console.ReadLine();
}

static public void a()
{
Console.WriteLine("a:" + Thread.CurrentThread.ManagedThreadId);
}

static public void b(Task t)
{
Console.WriteLine("b:" + Thread.CurrentThread.ManagedThreadId);
}

static public void c(Task t)
{
Console.WriteLine("c:" + Thread.CurrentThread.ManagedThreadId);
}

 

 

(29)C#多线程_数据_02

 

9.连续任务控制

使用TaskContinuationOptions的枚举成员,上一步出现某种问题时,来确定是否执行现在的方法

static void Main(string[] args)
{
Task task1 = new Task(a);
Task task2 = task1.ContinueWith(b,TaskContinuationOptions.DenyChildAttach);
task1.Start();
Console.WriteLine("end");
Console.ReadLine();
}

 

 10.任务的层次

 

11.

 

 

 ----------------------------------

Thread类

class Program
{
static void Main(string[] args)
{
Thread t1 = new Thread(M);
t1.Start();
//Thread.Sleep(1000);
Console.WriteLine("BBB");
Console.ReadKey();
}

static void M()
{

Console.WriteLine("AAA");
}
}

先输出AAA,还是BBB取决于操作系统调度

 

委托方式,输出结果和上列子相同

class Program
{
static void Main(string[] args)
{
Thread t1 = new Thread(() => Console.WriteLine("AAA"));
t1.Start();
Thread.Sleep(1000);
Console.WriteLine("BBB");
Console.ReadKey();
}
}

 

给线程传递数据

 方法一,启动线程时传递参数

class Program
{
static void Main(string[] args)
{
C c = new C { Message="hello" };
Thread t = new Thread(ThreadM);
t.Start(c);//线程启动时传参
Console.ReadKey();
}

static void ThreadM(object O)
{
C c = (C)O;
Console.WriteLine("AAA:{0}",c.Message);
}
}
public class C
{
public string Message;
}

方法二、自定义类

class Program
{
static void Main(string[] args)
{
C c = new C ("hello");
Thread t = new Thread(c.ThreadMain);
t.Start();
Console.ReadKey();
}
}
public class C
{
public string Message;
//构造函数
public C(string Message)
{
this.Message = Message;
}

public void ThreadMain()
{
Console.WriteLine("AAA:{0}",Message);
}
}

 

后台线程

前台线程可以有多个,后台线程也可以有多个。只要有一个前台线程在运行,程序的Main方法就不算结束。

Thread类创建的是前台线程。线城池中的线程时后台线程。

static void Main(string[] args)
{
//IsBackground默认为false,表示为前台线程
Thread t = new Thread(ThreadMain) { Name="线程",IsBackground=false};
t.Start();
Console.WriteLine("AAA");
Console.ReadKey();
}


public static void ThreadMain()
{
Console.WriteLine("{0}启动",Thread.CurrentThread.Name);
Thread.Sleep(6000);
}
}

如果IsBackground=false,按任意键后,会等执行完sleep方法才会结束。

如果IsBackground=true,按任意键后会立即结束。

这说明,如果有一个前台线程没执行完,Main方法就算都执行完,也要等到前台程序执行完才算是结束。

 

线程优先级

 线程的priority属性可以控制线程的优先级

它是一个枚举类型

Highest > AboveNormal > Normal > BelowNormal > Lowest

class Program
{
static void Main(string[] args)
{
Thread t1 = new Thread(ThreadMain) { Name = "A", Priority = ThreadPriority.Lowest };
Thread t2 = new Thread(ThreadMain) { Name = "B", Priority = ThreadPriority.Highest };
Thread t3 = new Thread(ThreadMain) { Name = "C", Priority = ThreadPriority.Normal };
t1.Start();
t2.Start();
t3.Start();
Console.ReadKey();
}
public static void ThreadMain()
{
Thread.Sleep(1000);
for (int i = 0; i < 5000; i++)
{
Console.Write("{0}", Thread.CurrentThread.Name);
}
}
}

线程优先级高的占用的CPU会更多一些

线程问题

争用条件

如果两个或多个线程访问相同的对象,并且对共享状态的访问没有同步,就会出现争用条件。

解决办法:加一个lock锁,只能锁引用类型

class Program
{
static object o = new object();
static void Main(string[] args)
{

}
public static void a()
{
lock (Program.o)
{
.....
}
}
}

死锁

锁定过多可能会引发死锁问题

同步

 



标签:Task,Console,Thread,C#,void,29,static,WriteLine,多线程
From: https://blog.51cto.com/u_13854953/5923138

相关文章

  • (64)C# 预处理器指令
     一、#define #undef 标记一个符号取消标记一个符号该指令要放在文件的开头 二、#if#elif #else#endif 符号还支持逻辑预算!==!= || 全局 定义trace常量相当......
  • JDBC 数据库连接池
    jdbc的链接//1.导入数据库驱动Class.forName("com.mysql.jdbc.Driver");//2.获取连接对象try{Stringurl="jdbc:mysql://localhost:3306/student?useSSL=false";//......
  • SourceTree免注册并连码云
    1在C:\Users\用户\AppData\Local\Atlassian\SourceTree目录下新建accounts.json其中AppData是隐藏文件夹2输入 [{"$id":"1","$type":"Sou......
  • Docker学习笔记十:Docker安装Nginx
    准备下载命令:dockerpullnginx安装可参考Docker Hub官网说明的镜像的用法  安装 第一步:简单安装创建容器命令:dockerrun-d--name=nginx-p8111:8080......
  • Elasticsearch xxx
    操作索引1添加put ​​http://192.168.1.1/index ​​index表示索引名称2查询get​​http://192.168.1.1/index ​​3关闭post http://192.168.1.1/index/_clos......
  • vue3.0 父组件显示子组件中的echarts,同时保证宽高自适应。
    目录vue3.0父组件显示子组件中的echarts,同时保证宽高自适应。el-card控件中的echarts进行填充布局示例代码vue3.0父组件显示子组件中的echarts,同时保证宽高自适应。父......
  • Codeforces Beta Round #2 C. Commentator problem
    题意二维平面上,给定三个圆的原点和半径,求一个点到三个圆的视角相同。三个圆心不共线。思路用(距离/半径)表示视角大小,用方差表示视角的波动。用爬山算法从重心开始四......
  • java dcm文件转图片
    1.情景展示如何将dicom文件转图片2.具体分析所需jar包<!--dcm文件转图片--><!--https://mvnrepository.com/artifact/org.dcm4che/dcm4che-core--><dependency>......
  • 三道MISC的writeup
    (1)背时描述:腐烂了,变异了,太背时了......附件为一个压缩包解题思路:1.打开压缩包,发现有一个描述:v(51wA:I7uABi#Bx(T2.将v(51wA:I7uABi#Bx(T进行Z85解密为c3npr_@aq_y0ir......
  • Abp:CSRF Anti Forgery
    文档https://docs.abp.io/en/abp/latest/CSRF-Anti-ForgeryCSRFAntiForgery的token什么时候写入Cookie的调用/api/abp/application-configuration时,设置Cookie......