先了解什么是异步什么是同步;
一、同步方法
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
//Main中调用
SyncMethod("一");
SyncMethod("二");
Console.WriteLine("--------主线程--------");
Console.ReadLine();
}
public static void SyncMethod(string str)
{
Console.WriteLine($"--------同步方法{str}--------");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(200);
Console.WriteLine($"同步:{i}");
}
}
}
}
二、异步方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
//异步方法
//Main中调用
AsyncMethod("一");
AsyncMethod("二");
Console.WriteLine("--------主线程--------");
Console.ReadLine();
}
public static void AsyncMethod(string str)
{
Console.WriteLine($"--------异步方法{str}--------");
Task.Run(() => {
for (int i = 0; i < 10; i++)
{
Thread.Sleep(200);
Console.WriteLine($"异步{str}:{i}");
}
});
}
}
}
三、Task开启线程的方法
public static void TaskTest()
{
//【1】new Task().Start()
Task task1 = new Task(() => { Console.WriteLine("Start开启一个子线程"); });
task1.Start();
//【1】实例化Task的一个重载,可传入委托需要用到的参数
Task task1_1 = new Task((inStr) => { Console.WriteLine($"Start开启一个子线程,入参{inStr}"); }, "入参AAA");
task1_1.Start();
//通过AsyncState 获取创建子线程时委托传入的参数值
string result = task1_1.AsyncState.ToString();
Console.WriteLine($"输出委托的传入参数:{result}");
//【2】Task.Run()
Task task2 = Task.Run(() => { Console.WriteLine("Run开启一个子线程"); });
//【2】Task.Run<TResult>表示一个可以返回值的异步操作
Task<long> task2_1 = Task.Run<long>(() =>
{
return DoSomethingLongTime();
});
long rst = task2_1.Result;//获取子线程返回的值
//【3】Task.Factory.StartNew
Task task3 = Task.Factory.StartNew(() => { Console.WriteLine("Factory.StartNew开启一个子线程"); });
//【3】Task.Factory.StartNew<TResult>
Task<long> task3_1 = Task.Factory.StartNew<long>(() =>
{
return DoSomethingLongTime();
});
long rst2 = task3_1.Result;
//另外还可以
TaskFactory task3_2 = new TaskFactory();
task3_2.StartNew(() => { Console.WriteLine("TaskFactory开启一个子线程"); });
//【4】new Task().RunSynchronously()同步执行,上述三种均是异步
Task task4 = new Task(() => { Console.WriteLine("Factory.StartNew开启一个子线程111"); });
task4.RunSynchronously();
Task task4_1 = new Task(() => { Console.WriteLine("Factory.StartNew开启一个子线程222"); });
task4_1.RunSynchronously();
Task task4_2 = new Task(() => { Console.WriteLine("Factory.StartNew开启一个子线程333"); });
task4_2.RunSynchronously();
Task task4_3 = new Task(() => { Console.WriteLine("Factory.StartNew开启一个子线程444"); });
task4_3.RunSynchronously();
//以上线程中的方法将会依次执行,不再异步执行
//【4】new Task().RunSynchronously()同步执行且带返回值的Task,(就当没开子线程)
Task<long> task4_4 = new Task<long>(() =>
{
return DoSomethingLongTime();
});
task4_4.RunSynchronously();
long resul = task4_4.Result;
}
//耗时操作
public static long DoSomethingLongTime()
{
long iResult = 0;
for (int i = 0; i < 1_000_000_000; i++)
{
iResult += i;
}
return iResult;
}
}
四、Task线程等待
(1)task.Wait()
static void Main(string[] args)
{
Console.WriteLine("----主线程--Start-----");
TaskTest();
Console.WriteLine("----主线程--End-----");
Console.ReadLine();
}
public static void TaskTest()
{
Task task1 = new Task(()=>
{
DoSomethingLongTime();
});
task1.Start();
//【1】内部执行完方可往下执行
task1.Wait();
//【2】指定等待的毫秒数,到指定毫秒后,不管是否执行完,都往下执行,相当于说好我要卡你主线程多久
task1.Wait(1000);
//作用同【2】,不过使用TimeSpan可以指定时分秒等更多的单位,更加的灵活
task1.Wait(TimeSpan.FromMilliseconds(1000));
}
//耗时任务
public static void DoSomethingLongTime()
{
long iResult = 0;
for (int i = 0; i < 1_000_000_000; i++)
{
iResult += i;
}
Console.WriteLine("耗时任务完成!");
//return iResult;
}
(2)Task.WaitAny()&Task.WaitAll()
static void Main(string[] args)
{
Console.WriteLine("----主线程--Start-----");
TaskTest();
Console.WriteLine("----主线程--End-----");
Console.ReadLine();
}
public static void TaskTest()
{
List<Task> taskList = new List<Task>();
Task task1 = Task.Run(() => { GetAlarmInfo("站点1"); });
Task task2 = Task.Run(() => { GetAlarmInfo("站点2"); });
Task task3 = Task.Run(() => { GetAlarmInfo("站点3"); });
taskList.Add(task1);
taskList.Add(task2);
taskList.Add(task3);
//Task.WaitAny需要传入一个Task的数组
Task.WaitAny(taskList.ToArray());
Console.WriteLine("有报警点查询到报警信息,需要报警");
//WaitAll等待所有的任务完成,才往后执行
//Task.WaitAll(taskList.ToArray());
//Console.WriteLine("所有报警点都查询到报警信息,紧急报警");
}
public static void GetAlarmInfo(string name)
{
Console.WriteLine($"Start--开始查询报警【{name}】的数据");
DoSomethingLongTime();//模拟查询任务
Console.WriteLine($"End--查询到报警【{name}】的数据");
}
public static void DoSomethingLongTime()
{
long iResult = 0;
for (int i = 0; i < 1_000_000_000; i++)
{
iResult += i;
}
}
(3)Task.WhenAny()&Task.WhenAll()&ContinueWith()
static void Main(string[] args)
{
Console.WriteLine("----主线程--Start-----");
//TaskTest(1);
TaskTest(2);
Console.WriteLine("----主线程--End-----");
Console.ReadLine();
}
public static void TaskTest(int flag)
{
List<Task> taskList = new List<Task>();
TaskFactory factory = new TaskFactory();
taskList.Add(factory.StartNew(() => { GetAlarmInfo("站点1"); }));
taskList.Add(factory.StartNew(() => { GetAlarmInfo("站点2"); }));
taskList.Add(factory.StartNew(() => { GetAlarmInfo("站点3"); }));
if (flag == 1)
{
//当传入的多个线程中任意一个线程执行完成后,继续执行执行ContinueWith中的任务(不卡主线程,因为新开了一个线程)
Task.WhenAny(taskList.ToArray()).ContinueWith((continuationAction) =>
{
Console.WriteLine($"【{flag}】-开始紧急报警");
DoSomethingLongTime();
Console.WriteLine($"【{flag}】-紧急报警完毕");
});
}
else
{
//当传入的多个线程都执行完成后,继续执行执行ContinueWith中的任务(不卡主线程,因为新开了一个线程)
Task.WhenAll(taskList.ToArray()).ContinueWith((continuationAction) =>
{
Console.WriteLine($"【{flag}】-开始紧急报警");
DoSomethingLongTime();
Console.WriteLine($"【{flag}】-紧急报警完毕");
});
}
}
public static void GetAlarmInfo(string name)
{
Console.WriteLine($"Start--开始查询报警【{name}】的数据");
DoSomethingLongTime();//模拟查询任务
Console.WriteLine($"End--查询到报警【{name}】的数据");
}
public static void DoSomethingLongTime()
{
long iResult = 0;
for (int i = 0; i < 1_000_000_000; i++)
{
iResult += i;
}
}
(4)ContinueWhenAny()&ContinueWhenAll()
if (flag == 1)
{
//当传入的多个线程中任意一个线程执行完成后,继续执行执行ContinueWith中的任务(不卡主线程,因为新开了一个线程)
Task.Factory.ContinueWhenAny(taskList.ToArray(), ((continuationAction) =>
{
Console.WriteLine($"【{flag}】-开始紧急报警");
DoSomethingLongTime();
Console.WriteLine($"【{flag}】-紧急报警完毕");
}));
}
else
{
//当传入的多个线程都执行完成后,继续执行执行ContinueWith中的任务(不卡主线程,因为新开了一个线程)
factory.ContinueWhenAll(taskList.ToArray(),((continuationAction) =>
{
Console.WriteLine($"【{flag}】-开始紧急报警");
DoSomethingLongTime();
Console.WriteLine($"【{flag}】-紧急报警完毕");
}));
}
五、线程返回值
(1)主线程中获取返回值,会阻塞主线程
private void TaskMethod1()
{
//这样子在主线程内获取返回值,会导致主线程阻塞
Task<long> task2_1 = Task.Run<long>(() =>
{
return DoSomethingLongTime1();
});
long rst = task2_1.Result;//获取子线程返回的值
}
(2)使用ContinueWith获取返回值,并做后续操作,不会阻塞线程,并且还可以连环使用返回值
private void TaskMethod2()
{
//使用ContinueWith会另外开一个线程不会卡顿
Task<long> task2_1 = Task.Run<long>(() =>
{
//Console.WriteLine(task2_1.Result.ToString());
//第一个任务的返回值,是无法在自己内部直接获取的
return DoSomethingLongTime1();
});
task2_1.ContinueWith(t =>
{
// 这里的 t 是一个带返回值的Task
// 通过 t.Result 可以取出上一个任务的返回值,然后再行使用
Console.WriteLine(t.Result.ToString());
return 2 + t.Result;
}).ContinueWith(s=>
{
//这里没有return ,系统自动识别是没有返回值的Task
Console.WriteLine(s.Result.ToString());
}) ;
}
(3)使用ContinueWhenAny和ContinueWhenAny获取返回值并作不同的操作,不会阻塞主线程
private void TaskMethod3()
{
List<Task<long>> tasks = new List<Task<long>>();
TaskFactory factory = new TaskFactory();
tasks.Add(factory.StartNew<long>(() => { return DoSomethingLongTime2(1); }));
tasks.Add(factory.StartNew<long>(() => { return DoSomethingLongTime2(2); }));
tasks.Add(factory.StartNew<long>(() => { return DoSomethingLongTime2(3); }));
tasks.Add(factory.StartNew<long>(() => { return DoSomethingLongTime2(4); }));
//在使用ContinueWhenAny获取第一个返回的数据
factory.ContinueWhenAny(tasks.ToArray(), (t) =>
{
Console.WriteLine($"第一个返回的结果:{t.Result}");
});
//使用ContinueWhenAll执行完所有任务后,找出最大值,最小值和结算总和
factory.ContinueWhenAll(tasks.ToArray(),(t)=>
{
long sumNum = 0;
long maxNum = t.Max(x => x.Result);
Console.WriteLine($"返回的最大值:{maxNum}");
long minNum = t.Min(x => x.Result);
Console.WriteLine($"返回的最小值:{minNum}");
long sum = t.Sum(x => x.Result);
Console.WriteLine($"返回的总和方式1:{sum}");
foreach (var item in t)
{
sumNum += item.Result;
};
Console.WriteLine($"返回的总和方式2:{sumNum}");
});
}
private long DoSomethingLongTime2(int id)
{
Console.WriteLine($"Start--耗时任务【{id}】开始");
long iResult = 0;
for (int i = 0; i < 1_000_000_000; i++)
{
iResult += i;
}
iResult += id;//这里只是为了后面对比大小使用
Console.WriteLine($"End--耗时任务【{id}】结束");
return iResult;
}