C#异步任务使用

C#异步任务使用

C#的异步编程升级过很多次语法,古老的异步使用方式我在之前的博文中写过,现在总结一下新的异步任务 Task/async/await 语法,新的异步编程方式,更简单,更实用,基本省去了使用一大堆回调方法的麻烦,而且也不用在实时维护多线程了,总之异步很强大和简洁,简洁是一种美德。

1. Task创建和运行
#region Task 创建和运行

//1.new方式实例化一个Task,需要通过Start方法启动
Task task1 = new Task(() =>
{
	Thread.Sleep(100);
	Console.WriteLine($"hello, task1的线程ID为{Thread.CurrentThread.ManagedThreadId}");
});
task1.Start();

//2.Task.Factory.StartNew(Action action)创建和启动一个Task
Task task2 = Task.Factory.StartNew(() =>
{
	Thread.Sleep(100);
	Console.WriteLine($"hello, task2的线程ID为{ Thread.CurrentThread.ManagedThreadId}");
});

//3.Task.Run(Action action)将任务放在线程池队列,返回并启动一个Task
Task task3 = Task.Run(() =>
{
	Thread.Sleep(100);
	Console.WriteLine($"hello, task3的线程ID为{ Thread.CurrentThread.ManagedThreadId}");
});
Console.WriteLine("执行主线程!");

#endregion

#region Task 泛型实例
1.new方式实例化一个Task,需要通过Start方法启动
Task<string> task4 = new Task<string>(() =>
{
	return $"hello, task1的ID为{Thread.CurrentThread.ManagedThreadId}";
});
task4.Start();
2.Task.Factory.StartNew(Func func)创建和启动一个Task
Task<string> task5 = Task.Factory.StartNew<string>(() =>
{
	return $"hello, task2的ID为{ Thread.CurrentThread.ManagedThreadId}";
});

3.Task.Run(Func func)将任务放在线程池队列,返回并启动一个Task
Task<string> task6 = Task.Run<string>(() =>
{
	return $"hello, task3的ID为{ Thread.CurrentThread.ManagedThreadId}";
});

Console.WriteLine("执行主线程!");
Console.WriteLine(task4.Result);
Console.WriteLine(task5.Result);
Console.WriteLine(task6.Result);
#endregion
2. 同步执行Task任务
//同步执行,task会阻塞主线程
task1.RunSynchronously();
Console.WriteLine("执行主线程结束!");
3. Task的阻塞方法

Wait,WaitAll,WaitAny

//阻塞主线程。task1,task2都执行完毕再执行主线程
//执行【task1.Wait();task2.Wait();】可以实现相同功能
Task.WaitAll(new Task[] { task1, task2 });
Console.WriteLine("主线程执行完毕!");
4. Task的延续操作

WhenAny,WhenAll,ContinueWith

Task.WhenAll(task1, task2).ContinueWith((t) => {
	Thread.Sleep(100);
	Console.WriteLine("执行后续操作完毕!");
});

//通过TaskFactroy实现
Task.Factory.ContinueWhenAll(new Task[] { task1, task2 }, (t) =>
{
	Thread.Sleep(100);
	Console.WriteLine("执行后续操作");
});
5. Task的任务取消
// Task的任务取消
CancellationTokenSource source = new CancellationTokenSource();
int index = 0;
//开启一个task执行任务
Task task7 = new Task(() =>
{
	while (!source.IsCancellationRequested)
	{
		Thread.Sleep(1000);
		Console.WriteLine($"第{++index}次执行,线程运行中...");
	}
});
task7.Start();
//五秒后取消任务执行
Thread.Sleep(5000);
//source.Cancel()方法请求取消任务,IsCancellationRequested会变成true
source.Cancel();

/*
CancellationTokenSource的功能不仅仅是取消任务执行,
我们可以使用 source.CancelAfter(5000) 实现5秒后自动取消任务,
也可以通过 source.Token.Register(Action action) 注册取消任务触发的回调函数,
即任务被取消时注册的action会被执行
*/
CancellationTokenSource source1 = new CancellationTokenSource();
//注册任务取消的事件
source.Token.Register(() =>
{
	Console.WriteLine("任务被取消后执行xx操作!");
});
int index1 = 0;
//开启一个task执行任务
Task task8 = new Task(() =>
{
	while (!source.IsCancellationRequested)
	{
		Thread.Sleep(1000);
		Console.WriteLine($"第{++index1}次执行,线程运行中...");
	}
});
task8.Start();
//延时取消,效果等同于Thread.Sleep(5000);source.Cancel();
source1.CancelAfter(5000);
6. 异步方法(async/await)
//异步方法(async/await)
string content = GetContentAsync(Environment.CurrentDirectory + @"/test.txt").Result;
//调用同步方法
//string content = GetContent(Environment.CurrentDirectory + @"/test.txt");
Console.WriteLine(content);

//异步读取文件内容
async static Task<string> GetContentAsync(string filename)
{

	FileStream fs = new FileStream(filename, FileMode.Open);
	var bytes = new byte[fs.Length];
	//ReadAync方法异步读取内容,不阻塞线程
	Console.WriteLine("开始读取文件");
	int len = await fs.ReadAsync(bytes, 0, bytes.Length);
	string result = Encoding.UTF8.GetString(bytes);
	return result;
}

//同步读取文件内容
static string GetContent(string filename)
{
	FileStream fs = new FileStream(filename, FileMode.Open);
	var bytes = new byte[fs.Length];
	//Read方法同步读取内容,阻塞线程
	int len = fs.Read(bytes, 0, bytes.Length);
	string result = Encoding.UTF8.GetString(bytes);
	return result;
}

7. 异步综合实例

// 异步方法实例
Task t = RunProgram();
t.Wait();
Console.ReadKey();

//测试函数
static async Task RunProgram()
{
	var taskQueue = new ConcurrentQueue<CustomTask>();
	var cts = new CancellationTokenSource();
	//生成任务添加至并发队列  
	var taskSource = Task.Run(() => TaskProducer(taskQueue));
	//同时启动四个任务处理队列中的任务  
	Task[] processors = new Task[4];
	for (int i = 1; i <= 4; i++)
	{
		string processId = i.ToString();
		processors[i - 1] = Task.Run(
			() => TaskProcessor(taskQueue, "Processor " + processId, cts.Token)
			);
	}
	await taskSource;
	//向任务发送取消信号  
	cts.CancelAfter(TimeSpan.FromSeconds(2));
	await Task.WhenAll(processors);
}

//产生任务
static async Task TaskProducer(ConcurrentQueue<CustomTask> queue)
{
	for (int i = 0; i < 20; i++)
	{
		await Task.Delay(50);
		var workItem = new CustomTask { Id = i };
		queue.Enqueue(workItem);
		Console.WriteLine("task {0} has been posted", workItem.Id);
	}
}

//执行任务
static async Task TaskProcessor(ConcurrentQueue<CustomTask> queue, string name, CancellationToken token)
{
	CustomTask workItem;
	bool dequeueSuccesful = false;
	await GetRandomDelay();
	do
	{
		dequeueSuccesful = queue.TryDequeue(out workItem);
		if (dequeueSuccesful)
		{
			Console.WriteLine("task {0} has been processed by {1}", workItem.Id, name);
		}
		await GetRandomDelay();
	}
	while (!token.IsCancellationRequested);
}

static Task GetRandomDelay()
{
	int delay = new Random(DateTime.Now.Millisecond).Next(1500);
	return Task.Delay(delay);
}

class CustomTask
{
	public int Id { get; set; }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值