【c#线程学习笔记三:任务Task】


文章目录

  • 一、Task的基本用法
    • 1.Task的启动
    • 2.Wait方法
    • 3.长任务
    • 4.Task的返回值
    • 5.Task的取消


一、Task的基本用法

1.Task的启动

Task代表着一个并发操作,启动一个基于线程Task的最简单方式是使用Task.Run(),调用时只需传入一个Action委托:

Task.Run(()=>Console.WriteLine("Hello"));

Task默认使用线程池中的线程,它们都是后台线程。

2.Wait方法

与线程的Join方法类型,调用Task的Wait方法可以阻塞当前方法,直到Task完成。

Task task = Task.Run(() =>
{
    Thread.Sleep(1000);
    Console.WriteLine("task print hello");
});
Console.WriteLine(task.IsCompleted);    //False
task.Wait();
Console.WriteLine(task.IsCompleted);    //True

可以在Wait中指定一个超时时间和取消令牌来提前终止等待状态。

3.长任务

默认情况下,CLR会将任务运行在线程池线程上,这种线程适合执行短小的计算密集的任务。如果要执行长时间阻塞的操作,则可以按照以下方式避免使用线程池线程:

Task task = Task.Factory.StartNew(() =>Console.WriteLine("hello"),TaskCreationOptions.LongRunning);

在线程池上运行一个长时间执行的任务并不会造成问题,但如果要并行运行多个长时间任务(特别是会造成阻塞的任务),则会对性能造成影响。
这种情况下,相比于使用TaskCreationOptions.LongRunning,更好的方案是:
①如果运行的是I/O密集型任务,则使用TaskCompletionSource和异步函数通过回调函数而非使用线程实现并发性
②如果任务是计算密集型,则使用生产者/消费者队列可以控制这些任务造成的并发数量,避免出现线程和进程饥饿的问题。

4.Task的返回值

Task由一个泛型子类 Task,它运行任务返回一个值。如果在调用Task.Run时传入一个 Func委托(或者兼容的Lambda表达式)替代Action就可以获得一个Task对象:

Task<int> task = Task.Run(() =>
{
    Console.WriteLine("into task");
    return 3;
});
Console.WriteLine(task.Result); // 输出3

5.Task的取消

    var cts = new CancellationTokenSource();
    try
    {
        var task = Task.Delay(100000, cts.Token);
        Thread.Sleep(2000);
        cts.Cancel();
        await task;
    }
    catch (TaskCanceledException e)
    {
        Console.WriteLine("Task canceled:" + e.Message);
    }
    finally { cts.Dispose(); }

你可能感兴趣的:(c#,学习,笔记)