异步编程(三)----TPL模式

异步编程的三种模式

c#三种异步编程模式

TAP模式(Task-based Asynchronous Pattern )

1. task 创建、运行并监控task 运行状态-

  1. Task 创建与运行
  • 这里需要注意的是:运行异步方法的线程是线程池中线程,默认是后台线程。当程序主线程结束时,若此时还有还后台线程在执行,则程序不会等待后台线程。

consoleApp项目,在main中添加如下代码

//TaskMethod()异步方法
var t1 = new Task(() => TaskMethod("task 1"));
            t1.Start();
            //lamda表达式
            Task.Run(() => TaskMethod("task 3"));
            Task.Factory.StartNew(() => TaskMethod("task 4"));
            Task.Factory.StartNew(() => TaskMethod("task 5"), TaskCreationOptions.LongRunning);

            

在main()下面添加如下代码

static int TaskMethod(string name)
        {
            Console.WriteLine($"task {name} is running on thread id:  {Thread.CurrentThread.ManagedThreadId}.Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}");
            Thread.Sleep(1000);
            return 42;
        }

2 . 查看task 的运行状态

          Task<int> task1 = new Task<int>(() => TaskMethod("task 1"));
            task1.Start();
            while (!task1.IsCompleted)
            {
                Console.WriteLine(task1.Status);
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
            }
            Console.WriteLine(task1.Status);
            Console.WriteLine("Result is: {0}", task1.Result);
           
            Console.ReadKey();

输出结果

WaitingToRun
task task 1 is running on thread id:  3.Is thread pool thread:True
Running
RanToCompletion
Result is: 42

2. 与APM模式比较

APM 中在异步方法执行完后,可以调用回调方法,执行后续操作。
Task中可调用ContinueWith()实现此效果。代码如下

var secondTask = new Task<int>(() => TaskMethod("second Task", 2));

            //task.ContinueWith:当异步方法完成,继续异步执行的操作,
            //类似APM中callback回调函数,仍然是异步执行
            secondTask.ContinueWith(
                t =>
                {
                    Console.WriteLine("second Task result:{0}", t.Result);
                    Console.WriteLine($"thread id :{Thread.CurrentThread.ManagedThreadId}");
                    Console.WriteLine($"is thread pool:{Thread.CurrentThread.IsThreadPoolThread}");
                });
            secondTask.Start();

          // 等待异步方法执行完成;
            Console.ReadKey();

main()下方添加如下代码

static int TaskMethod(string name, int seconds)
        {
            Console.WriteLine($"task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}." +
                $"Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}");
            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            return 42 * seconds;
        }

3. 与EAP模式比较

  1. EAP 转Task。注意异常处理
           var tcs = new TaskCompletionSource<int>();
            var worker = new BackgroundWorker();
            worker.DoWork += (sender, eventArgs) =>
            {
                eventArgs.Result = TaskMethod("Background worker", 5);
            };

            worker.RunWorkerCompleted += (sender, eventArgs) =>
            {
                if (eventArgs.Error != null)
                {
                    tcs.SetException(eventArgs.Error);
                }
                else if (eventArgs.Cancelled)
                {
                    tcs.SetCanceled();
                }
                else
                {
                    tcs.SetResult((int)eventArgs.Result);
                }
            };

            worker.RunWorkerAsync();

            int result = tcs.Task.Result;

            Console.WriteLine($"Result is:{result}");

4. task任务取消

  1. 调用Task.dispose(),无法销毁Task
    测试代码如下
           var firstTask = new Task<int>(() => TaskMethod("first Task", 10));

            firstTask.ContinueWith(
            t => Console.WriteLine($"the first answer is {t.Result}. " +
            $"thread id {Thread.CurrentThread.ManagedThreadId}. Is " +
            $"thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}"));

            firstTask.Start();
            System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
            stopwatch.Start();
            try
            {
                while (!firstTask.IsCompleted)
                {
                    Console.WriteLine(firstTask.Status);
                    Thread.Sleep(TimeSpan.FromSeconds(0.5));

                    TimeSpan ts = stopwatch.Elapsed;

                    if (ts > TimeSpan.FromSeconds(2))
                    {
                        stopwatch.Stop();
                        firstTask.Dispose();//处理这个异常,
                        break;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            Console.ReadLine();
            

输出结果,由此可见在调用task.dispose()后,task 仍在后台运行。

WaitingToRun
task first Task is running on a thread id 3.Is thread pool thread:True
Running
Running
Running
只有在任务处于完成状态(RanToCompletion、Faulted 或 Canceled)时才能释放它。
the first answer is 420. thread id 4. Is thread pool thread:True

  1. task取消,msdn example,msdn介绍
  2. 使用task取消机制,对异步方式设置timeout.
    虽然测试代码中实现了超时设置,但在实际应用中,如何监控cts.token.IsCancellationRequested的值,并不好设计。所以这种方式设置超时并不是最优选择。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.ComponentModel;

namespace Chapter4
{
    class Program
    {
        static void Main(string[] args)
        {
         
            var cts = new CancellationTokenSource();
            var timeoutTask = new Task<int>(() => TimeOutTask(1));timeout设置为1s
            var workTask = new Task<int>(() => TaskMethod5("work task", 4,cts.Token),cts.Token);
            var lstTask = new List<Task<int>>();
            lstTask.Add(timeoutTask);
            lstTask.Add(workTask);

            //监控workTask的运行状态 
            Task.Run(() =>
            {
                while (!workTask.IsCompleted)
                {
                    Console.WriteLine(workTask.Status);
                    Thread.Sleep(TimeSpan.FromSeconds(0.5));
                }
                Console.WriteLine(workTask.Status);
            });
            //监控workTask的运行状态

            timeoutTask.Start();
            workTask.Start();

            workTask.ContinueWith(t=> { Console.WriteLine($"work task result:{t.Result} .Is Canceled:{t.IsCanceled}"); });

            var completed = Task.WhenAny(lstTask).Result;
            Console.WriteLine($" completed task result:{completed.Result}");
            if (completed.Result == 1)
            {
                  //如果是超时先完成,则直接取消其他task
                cts.Cancel();
            }
            Thread.Sleep(TimeSpan.FromSeconds(0.5));

            Console.ReadLine();

        }
        static int TimeOutTask(int seconds)
        {
            Console.WriteLine($"timeout task is running on thread id:{Thread.CurrentThread.ManagedThreadId}");
            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            return seconds;
        }
        static int TaskMethod5(string name, int seconds,CancellationToken token)
        {
            Console.WriteLine("Task {0} is running on a thread id{1}. " +
                "Is thread pool thread: {2}", name, Thread.CurrentThread.ManagedThreadId,
               Thread.CurrentThread.IsThreadPoolThread);
            for (int i = 0; i < seconds; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(1));
                if (token.IsCancellationRequested)
                    token.ThrowIfCancellationRequested();
            }
            return 42 * seconds;
        }
    }
}

输出结果

Running
timeout task is running on thread id:5
Task work task is running on a thread id3. Is thread pool thread: True
Running
 completed task result:1
Running
Running
Running
Running
Canceled

5. task 并行编程

task.whenAll()与task.whenAny()
测试代码。

Task.WhenAny method. 可以用来设置超时,异步运行tasks时,设置一个task用来计时,如果计时的task已经完成,还有task未完成,这取消未完成的task.但是如何在异步方法中监控cts.token.IsCancellationRequested不好设计。

6. async/await 使用

async/await-BestPractices-msdn

async/await 方法执行流程。
在这里插入图片描述
执行流程
在这里插入图片描述

c#异步编程

tsak 异步编程使用

  • 当程序中有大量I/O操作(如:读写数据库、上传或下载数据、读取或写入文件)等操作时,可以考虑使用异步
  • 当程序中耗时的操作时,可以使用task.run()方式,在后台线程中调用耗时方法。

注意事项

  • Calling the async method includes a significant performance hit, and the usual method call is going to be about 40 to 50 times faster as compared to the same method marked with the async keyword. Please be aware of that.
    正常调用方法比使用async 关键字快40~50倍。

Please remember that it is not recommended to use the Task.Wait and Task.Result methods in environments, such as Windows GUI or ASP.NET. This could lead to deadlocks if
the programmer is not 100% aware of what is really going on in the code

  • If we use the catch block the same way as before, we will get only
    the first exception from the underlying AggregateException object.
    如果使用 try catch 捕捉two wait ,只会抓到第一个异常
    除非在UI eventHandlers中,使用async void ,其他情况下强烈建议用async task。主要是async void的exception 可能使整个应用程序崩溃。

  • I strongly recommended using async void only in UI event handlers. In all other situations,
    use the methods that return Task instead.

APM模式(Asynchronous-Programming-Model)

AMP使用介绍

EAP模式(Event-based Asynchronous Pattern)

EAP模式使用介绍

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值