异步方法

注意,异步方法是C# 5.0后增加

异步(async)方法:用于异步执行其他工作,然后立即返回到调用方法。

await 表达式:用于异步方法内部,指明需要异步执行的任务。一个异步方法可以包含任意多个await表达式,如果一个都不包含的话编译器会发出警告。



  class MyDownloadString
    {
        Stopwatch sw = new Stopwatch();


        public void DoRun()
        {
            const int LargeNumber = 600;
            sw.Start();
            Task<int> t1 = CountCharactersAsync(1, "http://www.microsoft.com");
            Task<int> t2 = CountCharactersAsync(2, "http://illustratedcsharp.com");


            CountToALargeNumber(1, LargeNumber);
            CountToALargeNumber(2, LargeNumber);
            CountToALargeNumber(3, LargeNumber);
            CountToALargeNumber(4, LargeNumber);


            Console.WriteLine("Chars in http://www.microsoft.com    :{0}", t1.Result);
            Console.WriteLine("Chars in http://www.illustratedcsharp.com    :{0}", t2.Result);
        }

        //返回值 Task<int>
        private async Task<int> CountCharactersAsync(int id, string uriString)
        {
            WebClient wc1 = new WebClient();
            Console.WriteLine("Starting call {0} :  {1,4:N0} ms", id, sw.Elapsed.TotalMilliseconds);
            string result = await wc1.DownloadStringTaskAsync(new Uri(uriString));
            Console.WriteLine(" call {0} completed:     {1,4:N0} ms", id, sw.Elapsed.TotalMilliseconds);
            return result.Length;
        }

     //返回值 Task<int>
        public static async Task<int> TaskIntAsync()
        {
            int a = 5, b = 6;
            int sum = await Task.Run(() => Sum(a, b));
            return sum;
        }

//返回值 Task
        public static async Task TaskAsync()
        {
            string a = "task";
            await Task.Run(() => Print(ref a));
        }

//返回值 Void
        public static async void VoidAsync()
        {
            string a = "void";

            await Task.Run(() => Print(ref a));

//此处return无效

        }


        public static int Sum(int a, int b)
        {
            return a + b;
        }


        public static void Print(ref string a)
        {
            Console.WriteLine(a);
        }
        private void CountToALargeNumber(int id, int value)
        {
            for (long i = 0; i < value; i++)
            {
                Console.WriteLine("  End counting {0}   :  {1,4:N0} ms", id, sw.Elapsed.TotalMilliseconds);
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyDownloadString ds = new MyDownloadString();
            //ds.DoRun();
            Task<int> result = MyDownloadString.TaskIntAsync();
            Console.WriteLine(result.Result);
            MyDownloadString.VoidAsync();
            Task task =  MyDownloadString.TaskAsync();
            task.Wait();
            Thread.Sleep(1000);
            Console.WriteLine("执行主线程了啊啊啊a");
            Console.ReadKey();
        }

    }

======================================================================

取消异步操作

System.Threading.Task命名空间中有两个类是为此目的而设计的。CancellationToken和CancellationTokenSource

1.CancellationToken 对象包含一个任务十分应被取消的信息。

2.拥有CancellationToken 对象的任务需求要定期检查其令牌(token)状态。如果CancellationToken 对象的IsCancellationRequested属性为true,任务需停止其操作并返回。

3.CancellationToken是不可逆的,并且只能使用一次,一旦IsCancellationRequested属性被设置为true,就不能更改。

4.CancellationTokenSource对象创建可分批给不同任务的CancellationToken对象。任何有CancellationTokenSource的对象都可以条用其Cancel方法,这会将CancellationToken的IsCancellationRequested属性设置为true。


 public class Program
    {
        public static void Main(string[] args)
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            CancellationToken token = cts.Token;
            MyClass mc = new MyClass();
            Task t = mc.RunAsync(token);


            Thread.Sleep(3000);//等待3秒
            cts.Cancel();//取消操作


            t.Wait();
            Console.WriteLine("Was Cancelled:{0}",token.IsCancellationRequested);
            Console.ReadKey();
        }
    }


    class MyClass
    {
        public async Task RunAsync(CancellationToken ct)
        {


            if (ct.IsCancellationRequested)
            {
                return;
            }


            await Task.Run(() => CycleMethod(ct),ct);
        }


        void CycleMethod(CancellationToken ct)
        {
            Console.WriteLine("Starting CycleMethod");
            const int max = 5;
            for (int i = 0; i < max; i++)
            {
                if (ct.IsCancellationRequested)
                {
                    return;
                }
                Thread.Sleep(1000);
                Console.WriteLine("     {0} of {1} iterations completed", i + 1, max);
            }
        }

    }

==========================================================================

在异常调用中同步等待

调用方法可以调用任意多个异步方法并接收他们返回的Task对象,然后你的代码会继续执行其他任务,在某个点需要等待某个特殊Task对象完成,然后继续。为此Task提供了一个Wait,可以在Task对象上调用。

 public class Program
    {
        public static void Main(string[] args)
        {
            Task t = BadAsync();
            t.Wait();
            Console.WriteLine("Task Status  :  {0}", t.Status);
            Console.WriteLine("Task IsFaulted:{0}", t.IsFaulted);
            Console.ReadKey();
        }


        static async Task BadAsync()
        {
            try
            {
                await Task.Run(() => { throw new Exception(); });
            }
            catch
            {
                Console.WriteLine("Exception in BadAsync");
            }
        }

    }

==========================================================================

在异常调用中异步等待

使用Task.WhenAll和Task.WhenAny方法来实现等待一个或所有任务完成。

  static class MyDownloadString
    {
        public static void DoRun()
        {
            Task<int> t = CountCharactersAsync("http://www.illustratedcsharp.com", "http://www.illustratedcsharp.com");
            //t.Wait();
            Console.WriteLine("The task has finished returning value{0}.", t.Result);
            Console.ReadKey();
        }


        public static async Task<int> CountCharactersAsync(string site1, string site2)
        {
           
            WebClient wc1 = new WebClient();
            WebClient wc2 = new WebClient();
            Task<string> t1 = wc1.DownloadStringTaskAsync(new Uri(site1));
            Task<string> t2 = wc2.DownloadStringTaskAsync(new Uri(site2));


            List<Task<string>> tasks = new List<Task<string>>();
            tasks.Add(t1);
            tasks.Add(t2);
            await Task.WhenAll(tasks);


            Console.WriteLine("CCA: T1{0} finished", t1.IsCompleted);
            Console.WriteLine("CCA: T2{0} finished", t2.IsCompleted);


            return t1.IsCompleted ? t1.Result.Length : t2.Result.Length;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyDownloadString.DoRun();
        }

    }

Task.Delay方法

Task.Delay对象将暂停其在线程中的处理,并在一定时间之后完成。于Thread.Sleep阻塞不同的是,Task.Delay不会阻塞线程,线程可以继续处理其他工作。

    //Task.Delay方法
    //创建一个Task对象,该对象将暂停其在线程中的处理,并在一定时间后完成,然后与Thread,Sleep阻塞线程不同的是,Task.Delay不会阻塞线程,线程可以继续处理其他工作。
    class Simple
    {
        Stopwatch sw = new Stopwatch();
        public void DoRun()
        {
            Console.WriteLine("Caller:Before call");
            ShowDelayAsync();
            Console.WriteLine("Caller:After call");
        }


        private async void ShowDelayAsync()
        {
            sw.Start();
            Console.WriteLine("     Before Delay:{0}", sw.ElapsedMilliseconds);
            await Task.Delay(1000);
            Console.WriteLine("     After Delay:{0}", sw.ElapsedMilliseconds);
        }
    }
    class Program
    {


        static void Main(string[] args)
        {
            Simple ds = new Simple();
            ds.DoRun();
            Console.Read();
        }
    }

}


============================================================================

完整的例子

 public partial class Form1 : Form
    {
        CancellationTokenSource _cancellationToKenSource;
        CancellationToken _cancellationToken;
        public Form1()
        {
            InitializeComponent();
        }


        private void Form1_Load(object sender, EventArgs e)
        {


        }


        private async void button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            button2.Enabled = true;
            _cancellationToKenSource = new CancellationTokenSource();
            _cancellationToken = _cancellationToKenSource.Token;
            int completedPercent = 0;


            for (int i = 0; i < 10; i++)
            {
                if (_cancellationToken.IsCancellationRequested)
                {
                    break;
                }
                try
                {
                    await Task.Delay(500, _cancellationToken);
                    completedPercent = (i+1) * 10;
                }
                catch (TaskCanceledException ex)
                {
                    completedPercent = i * 10;
                }


                progressBar1.Value = completedPercent;
            }
            string message = _cancellationToken.IsCancellationRequested?string.Format("Process was cancelled at {0}%.",completedPercent):"Process completed normally.";
            MessageBox.Show(message,"Completion Satus");


            progressBar1.Value = 0;
           
           
        }


        private void button2_Click(object sender, EventArgs e)
        {
            if(!button1.Enabled){
                button2.Enabled = false;
                _cancellationToKenSource.Cancel();
            }
           
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值