第5章 使用C#6.0

  • 简介
  • 使用await操作符获取异步任务结果
using System;
using System.Threading.Tasks;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter5.Recipe1
{
	class Program
	{
		static void Main(string[] args)
		{
			Task t = AsynchronyWithTPL();
			t.Wait();

			t = AsynchronyWithAwait();
			t.Wait();
		}

		static Task AsynchronyWithTPL()
		{
			Task<string> t = GetInfoAsync("Task 1");
			Task t2 = t.ContinueWith(task => WriteLine(t.Result),
				TaskContinuationOptions.NotOnFaulted);
			Task t3 = t.ContinueWith(task => WriteLine(t.Exception.InnerException),
				TaskContinuationOptions.OnlyOnFaulted);

			return Task.WhenAny(t2, t3);
		}

		static async Task AsynchronyWithAwait()
		{
			try
			{
				string result = await GetInfoAsync("Task 2");
				WriteLine(result);
			}
			catch (Exception ex)
			{
				WriteLine(ex);
			}
		}

		static async Task<string> GetInfoAsync(string name)
		{
			await Task.Delay(TimeSpan.FromSeconds(2));
			//throw new Exception("Boom!");
			return
			    $"Task {name} is running on a thread id {CurrentThread.ManagedThreadId}." + 
                $" Is thread pool thread: {CurrentThread.IsThreadPoolThread}";
		}
	}
}

  • 在lambda表达式中使用await操作符
using System;
using System.Threading.Tasks;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter5.Recipe2
{
	class Program
	{
		static void Main(string[] args)
		{
			Task t = AsynchronousProcessing();
			t.Wait();
		}

		static async Task AsynchronousProcessing()
		{
			Func<string, Task<string>> asyncLambda = async name => {
				await Task.Delay(TimeSpan.FromSeconds(2));
				return
				    $"Task {name} is running on a thread id {CurrentThread.ManagedThreadId}." +
				    $" Is thread pool thread: {CurrentThread.IsThreadPoolThread}";
			};

			string result = await asyncLambda("async lambda");

			WriteLine(result);
		}
	}
}

  • 对连续的异步任务使用await操作符
using System;
using System.Threading.Tasks;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter5.Recipe3
{
	class Program
	{
		static void Main(string[] args)
		{
			Task t = AsynchronyWithTPL();
			t.Wait();

			t = AsynchronyWithAwait();
			t.Wait();
		}

		static Task AsynchronyWithTPL()
		{
			var containerTask = new Task(() => { 
				Task<string> t = GetInfoAsync("TPL 1");
				t.ContinueWith(task => {
					WriteLine(t.Result);
					Task<string> t2 = GetInfoAsync("TPL 2");
					t2.ContinueWith(innerTask => WriteLine(innerTask.Result),
						TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.AttachedToParent);
					t2.ContinueWith(innerTask => WriteLine(innerTask.Exception.InnerException),
						TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent);
					},
					TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.AttachedToParent);

				t.ContinueWith(task => WriteLine(t.Exception.InnerException),
					TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent);
			});

			containerTask.Start();
			return containerTask;
		}

		static async Task AsynchronyWithAwait()
		{
			try
			{
				string result = await GetInfoAsync("Async 1");
				WriteLine(result);
				result = await GetInfoAsync("Async 2");
				WriteLine(result);
			}
			catch (Exception ex)
			{
				WriteLine(ex);
			}
		}

		static async Task<string> GetInfoAsync(string name)
		{
			WriteLine($"Task {name} started!");
			await Task.Delay(TimeSpan.FromSeconds(2));
			if(name == "TPL 2")
				throw new Exception("Boom!");
			return
			    $"Task {name} is running on a thread id {CurrentThread.ManagedThreadId}." +
			    $" Is thread pool thread: {CurrentThread.IsThreadPoolThread}";
		}
	}
}
  • 对并行执行的异步任务使用await操作符
using System;
using System.Threading.Tasks;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter5.Recipe4
{
	class Program
	{
		static void Main(string[] args)
		{
			Task t = AsynchronousProcessing();
			t.Wait();
		}

		static async Task AsynchronousProcessing()
		{
			Task<string> t1 = GetInfoAsync("Task 1", 3);
			Task<string> t2 = GetInfoAsync("Task 2", 5);

			string[] results = await Task.WhenAll(t1, t2);
			foreach (string result in results)
			{
				WriteLine(result);
			}
		}

		static async Task<string> GetInfoAsync(string name, int seconds)
		{
			await Task.Delay(TimeSpan.FromSeconds(seconds));
			//await Task.Run(() => Thread.Sleep(TimeSpan.FromSeconds(seconds)));
			return
			    $"Task {name} is running on a thread id {CurrentThread.ManagedThreadId}." +
			    $" Is thread pool thread: {CurrentThread.IsThreadPoolThread}";
		}
	}
}

  • 处理异步操作中的异常
using System;
using System.Threading.Tasks;
using static System.Console;

namespace Chapter5.Recipe5
{
	class Program
	{
		static void Main(string[] args)
		{
			Task t = AsynchronousProcessing();
			t.Wait();
		}

		static async Task AsynchronousProcessing()
		{
			WriteLine("1. Single exception");

			try
			{
				string result = await GetInfoAsync("Task 1", 2);
				WriteLine(result);
			}
			catch (Exception ex)
			{
				WriteLine($"Exception details: {ex}");
			}

			WriteLine();
			WriteLine("2. Multiple exceptions");

			Task<string> t1 = GetInfoAsync("Task 1", 3);
			Task<string> t2 = GetInfoAsync("Task 2", 2);
			try
			{
				string[] results = await Task.WhenAll(t1, t2);
				WriteLine(results.Length);
			}
			catch (Exception ex)
			{
				WriteLine($"Exception details: {ex}");
			}

			WriteLine();
			WriteLine("3. Multiple exceptions with AggregateException");

			t1 = GetInfoAsync("Task 1", 3);
			t2 = GetInfoAsync("Task 2", 2);
			Task<string[]> t3 = Task.WhenAll(t1, t2);
			try
			{
				string[] results = await t3;
				WriteLine(results.Length);
			}
			catch
			{
				var ae = t3.Exception.Flatten();
				var exceptions = ae.InnerExceptions;
				WriteLine($"Exceptions caught: {exceptions.Count}");
				foreach (var e in exceptions)
				{
					WriteLine($"Exception details: {e}");
					WriteLine();
				}
			}

            WriteLine();
            WriteLine("4. await in catch and finally blocks");

		    try
		    {
		        string result = await GetInfoAsync("Task 1", 2);
		        WriteLine(result);
		    }
		    catch (Exception ex)
		    {
		        await Task.Delay(TimeSpan.FromSeconds(1));
		        WriteLine($"Catch block with await: Exception details: {ex}");
		    }
		    finally
		    {
                await Task.Delay(TimeSpan.FromSeconds(1));
                WriteLine("Finally block");
		    }
        }

		static async Task<string> GetInfoAsync(string name, int seconds)
		{
			await Task.Delay(TimeSpan.FromSeconds(seconds));
			throw new Exception($"Boom from {name}!");
		}
	}
}

  • 避免使用捕获的同步上下文
using System;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using static System.Console;


namespace Chapter5.Recipe6
{
	class Program
	{
		[STAThread]
		static void Main(string[] args)
		{
			var app = new Application();
			var win = new Window();
			var panel = new StackPanel();
			var button = new Button();
			_label = new Label();
			_label.FontSize = 32;
			_label.Height = 200;
			button.Height = 100;
			button.FontSize = 32;
			button.Content = new TextBlock {Text = "Start asynchronous operations"};
			button.Click += Click;
			panel.Children.Add(_label);
			panel.Children.Add(button);
			win.Content = panel;
			app.Run(win);

			ReadLine();
		}

		static async void Click(object sender, EventArgs e)
		{
			_label.Content = new TextBlock {Text = "Calculating..."};
			TimeSpan resultWithContext = await Test();
			TimeSpan resultNoContext = await TestNoContext();
			//TimeSpan resultNoContext = await TestNoContext().ConfigureAwait(false);
			var sb = new StringBuilder();
			sb.AppendLine($"With the context: {resultWithContext}");
			sb.AppendLine($"Without the context: {resultNoContext}");
			sb.AppendLine("Ratio: " +
			    $"{resultWithContext.TotalMilliseconds/resultNoContext.TotalMilliseconds:0.00}");
			_label.Content = new TextBlock {Text = sb.ToString()};
		}

		static async Task<TimeSpan> Test()
		{
			const int iterationsNumber = 100000;
			var sw = new Stopwatch();
			sw.Start();
			for (int i = 0; i < iterationsNumber; i++)
			{
				var t = Task.Run(() => { });
				await t;
			}
			sw.Stop();
			return sw.Elapsed;
		}

		static async Task<TimeSpan> TestNoContext()
		{
			const int iterationsNumber = 100000;
			var sw = new Stopwatch();
			sw.Start();
			for (int i = 0; i < iterationsNumber; i++)
			{
				var t = Task.Run(() => { });
				await t.ConfigureAwait(
					continueOnCapturedContext: false);
			}
			sw.Stop();
			return sw.Elapsed;
		}

		private static Label _label;
	}
}

  • 使用async void方法
using System;
using System.Threading.Tasks;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter5.Recipe7
{
	class Program
	{
		static void Main(string[] args)
		{
			Task t = AsyncTask();
			t.Wait();

			AsyncVoid();
			Sleep(TimeSpan.FromSeconds(3));

			t = AsyncTaskWithErrors();
			while(!t.IsFaulted)
			{
				Sleep(TimeSpan.FromSeconds(1));
			}
			WriteLine(t.Exception);

			//try
			//{
			//	AsyncVoidWithErrors();
			//	Thread.Sleep(TimeSpan.FromSeconds(3));
			//}
			//catch (Exception ex)
			//{
			//	Console.WriteLine(ex);
			//}

			int[] numbers = {1, 2, 3, 4, 5};
			Array.ForEach(numbers, async number => {
				await Task.Delay(TimeSpan.FromSeconds(1));
				if (number == 3) throw new Exception("Boom!");
				WriteLine(number);
			});

			ReadLine();
		}

		static async Task AsyncTaskWithErrors()
		{
			string result = await GetInfoAsync("AsyncTaskException", 2);
			WriteLine(result);
		}

		static async void AsyncVoidWithErrors()
		{
			string result = await GetInfoAsync("AsyncVoidException", 2);
			WriteLine(result);
		}

		static async Task AsyncTask()
		{
			string result = await GetInfoAsync("AsyncTask", 2);
			WriteLine(result);
		}

		static async void AsyncVoid()
		{
			string result = await GetInfoAsync("AsyncVoid", 2);
			WriteLine(result);
		}

		static async Task<string> GetInfoAsync(string name, int seconds)
		{
			await Task.Delay(TimeSpan.FromSeconds(seconds));
			if(name.Contains("Exception"))
				throw new Exception($"Boom from {name}!");
			return
			    $"Task {name} is running on a thread id {CurrentThread.ManagedThreadId}." +
			    $" Is thread pool thread: {CurrentThread.IsThreadPoolThread}";
		}
	}
}

  • 设计一个自定义的awaitable类型
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter5.Recipe8
{
	class Program
	{
		static void Main(string[] args)
		{
			Task t = AsynchronousProcessing();
			t.Wait();
		}

		static async Task AsynchronousProcessing()
		{
			var sync = new CustomAwaitable(true);
			string result = await sync;
			WriteLine(result);

			var async = new CustomAwaitable(false);
			result = await async;

			WriteLine(result);
		}

		class CustomAwaitable
		{
			public CustomAwaitable(bool completeSynchronously)
			{
				_completeSynchronously = completeSynchronously;
			}

			public CustomAwaiter GetAwaiter()
			{
				return new CustomAwaiter(_completeSynchronously);
			}

			private readonly bool _completeSynchronously;
		}

		class CustomAwaiter : INotifyCompletion
		{
			private string _result = "Completed synchronously";
			private readonly bool _completeSynchronously;

			public bool IsCompleted => _completeSynchronously;

		    public CustomAwaiter(bool completeSynchronously)
			{
				_completeSynchronously = completeSynchronously;
			}

			public string GetResult()
			{
				return _result;
			}

			public void OnCompleted(Action continuation)
			{
				ThreadPool.QueueUserWorkItem( state => {
					Sleep(TimeSpan.FromSeconds(1));
					_result = GetInfo();
				    continuation?.Invoke();
				});
			}

			private string GetInfo()
			{
				return
				    $"Task is running on a thread id {CurrentThread.ManagedThreadId}." +
				    $" Is thread pool thread: {CurrentThread.IsThreadPoolThread}";
			}
		}
	}
}

  • 对动态类型使用await
using System;
using System.Dynamic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using ImpromptuInterface;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter5.Recipe9
{
	class Program
	{
		static void Main(string[] args)
		{
			Task t = AsynchronousProcessing();
			t.Wait();
		}

		static async Task AsynchronousProcessing()
		{
			string result = await GetDynamicAwaitableObject(true);
			WriteLine(result);

			result = await GetDynamicAwaitableObject(false);
			WriteLine(result);
		}

		static dynamic GetDynamicAwaitableObject(bool completeSynchronously)
		{
			dynamic result = new ExpandoObject();
			dynamic awaiter = new ExpandoObject();

			awaiter.Message = "Completed synchronously";
			awaiter.IsCompleted = completeSynchronously;
			awaiter.GetResult = (Func<string>)(() => awaiter.Message);

			awaiter.OnCompleted = (Action<Action>) ( callback => 
				ThreadPool.QueueUserWorkItem(state => {
					Sleep(TimeSpan.FromSeconds(1));
					awaiter.Message = GetInfo();
				    callback?.Invoke();
				})
			);

			IAwaiter<string> proxy = Impromptu.ActLike(awaiter);

			result.GetAwaiter = (Func<dynamic>) ( () => proxy );

			return result;
		}

		static string GetInfo()
		{
			return
			    $"Task is running on a thread id {CurrentThread.ManagedThreadId}." +
			    $" Is thread pool thread: {CurrentThread.IsThreadPoolThread}";
		}
    }

    public interface IAwaiter<T> : INotifyCompletion
    {
        bool IsCompleted { get; }

        T GetResult();
    }
}

posted on 2019-05-14 17:06  威武的祥哥  阅读(146)  评论(0)    收藏  举报

导航