近来在看《C# 并发编程 · 典范实例》这本书,这不是一本理论书,反而这是一本重要报告怎样更好的运用好现在 C#.NET 为我们供应的这些 API 的一本书,书中绝大部分是一些实例,在一样平常开辟中照样常常会运用到。
书中一些看法照样比较赞许,比方作者说现在绝大多数的图书对关于并发多线程等这些内容放到末了,而缺乏一本引见并发编程的入门指引和参考。
别的一个看法是绝大多数国内的手艺人员以为手艺越底层就牛逼,而做上层运用的就是“码农”,作者反对了这一看法,实在能利用好现有的库也是一种才能,虽然说明白基本知识对一样平常生活依然有协助,但最好从更高等的抽象概念来进修。
异步基本
使命停息,休眠
异步体式格局停息或许休眠使命,能够运用 Task.Delay();
static async Task<T> DelayResult<T>(T result, TimeSpan delay) { await Task.Delay(delay); return result; }
异步重试机制
一个简朴的指数退避战略,重试的时刻会逐次增添,在接见 Web 效劳时,平常采纳此种战略。
static async Task<string> DownloadString(string uri) { using (var client = new HttpClient()) { var nextDealy = TimeSpan.FromSeconds(1); for (int i = 0; i != 3; ++i) { try { return await client.GetStringAsync(uri); } catch { } await Task.Delay(nextDealy); nextDealy = nextDealy + nextDealy; } //末了重试一次,抛出失足信息 return await client.GetStringAsync(uri); } }
报告进度
异步操纵中,常常须要展现操纵进度,能够运用 IProcess<T> 和 Process<T>。
static async Task MyMethodAsync(IProgress<double> progress) { double precentComplete = 0; bool done = false; while (!done) { await Task.Delay(100); if (progress != null) { progress.Report(precentComplete); } precentComplete++; if (precentComplete == 100) { done = true; } } } public static void Main(string[] args) { Console.WriteLine("starting..."); var progress = new Progress<double>(); progress.ProgressChanged += (sender, e) => { Console.WriteLine(e); }; MyMethodAsync(progress).Wait(); Console.WriteLine("finished"); }
守候一组使命
同时实行几个使命,守候他们悉数完成
Task task1 = Task.Delay(TimeSpan.FromSeconds(1)); Task task2 = Task.Delay(TimeSpan.FromSeconds(2)); Task task3 = Task.Delay(TimeSpan.FromSeconds(1)); Task.WhenAll(task1, task2, task3).Wait();
守候恣意一个使命完成
实行多少使命,只须要对个中一个的完成举行相应。重要用于对一个操纵举行多种自力的尝试,只需个中一个尝试完成,使命就算完成。
static async Task<int> FirstResponseUrlAsync(string urlA, string urlB) { var httpClient = new HttpClient(); Task<byte[]> downloadTaskA = httpClient.GetByteArrayAsync(urlA); Task<byte[]> downloadTaskB = httpClient.GetByteArrayAsync(urlB); Task<byte[]> completedTask = await Task.WhenAny(downloadTaskA, downloadTaskB); byte[] data = await completedTask; return data.Length; }
鸠合
不可变栈和行列
须要一个不会常常修正,能够被多个线程平安接见的栈和行列。他们的API和 Stack<T> 和 Queue<T> 异常类似。机能上,不可变栈(LIFO)和行列(FIFO)与规范的栈和行列具有雷同的时刻复杂度。然则在须要频仍修正的简朴情况下,规范栈和行列速率更快。
在内部完成上,当对一个对象举行掩盖(从新赋值)的时刻,不可变鸠合采纳的是返回一个修正过的鸠合,原始鸠合引用是不变化的,也就是说假如别的一个变量引用了雷同的对象,那末它(别的的变量)是不会变化的。
ImmutableStack
var stack = ImmutableStack<int>.Empty; stack = stack.Push(11); var biggerstack = stack.Push(12); foreach (var item in biggerstack) { Console.WriteLine(item); } // output: 12 11 int lastItem; stack = stack.Pop(out lastItem); Console.WriteLine(lastItem); //output: 11
实际上,两个栈内部同享了存储 11 的内存,这类完成体式格局效力很高,而且每一个实例都是线程平安的。
ImmutableQueue
var queue = ImmutableQueue<int>.Empty; queue = queue.Enqueue(11); queue = queue.Enqueue(12); foreach (var item in queue) { Console.WriteLine(item); } // output: 11 12 int nextItem; queue = queue.Dequeue(out nextItem); Console.WriteLine(nextItem); //output: 11
不可变列表和鸠合
ImmutableList
时刻复杂度
有些时刻须要如许一个数据结构:支撑索引,不常常修正,能够被多线程平安的接见。
var list = ImmutableList<int>.Empty; list = list.Insert(0, 11); list = list.Insert(0, 12); foreach (var item in list) { Console.WriteLine(item); } // 12 11
ImmutableList<T> 能够索引,然则注重机能题目,不能用它来简朴的替换 List<T>。它的内部完成是用的二叉树构造的数据,这么做是为了让差别的实例之间同享内存。
ImmutableHashSet
有些时刻须要如许一个数据结构:不须要寄存反复内容,不常常修正,能够被多个线程平安接见。时刻复杂度 O(log N)。
var set = ImmutableHashSet<int>.Empty; set = set.Add(11); set = set.Add(12); foreach (var item in set) { Console.WriteLine(item); } // 11 12 递次不定
线程平安字典
一个线程平安的键值对鸠合,多个线程读写依然能坚持同步。
ConcurrentDictionary
夹杂运用了细粒度的锁定和无锁手艺,它是最有用的鸠合范例之一。
var dictionary = new ConcurrentDictionary<int, string>(); dictionary.AddOrUpdate(0, key => "Zero", (key, oldValue) => "Zero");
假如多个线程读写一个同享鸠合,有用 ConcurrentDictionary<TKey,TValue> 是最合适的。假如不会频仍修正,那末更合适运用 ImmutableDictionary<TKey,TValue> 。
它最合适用于在须要同享数据的场所,即多个线程同享一个鸠合,假如一些线程只增加元素一些线程只移除元素,那最好运用 生产者/消费者鸠合(BlockingCollection<T>)。
初始化同享资源
顺序多个处所运用一个值,第一次接见时对它举行初始化。
static int _simpleVluae; static readonly Lazy<Task<int>> shardAsyncInteger = new Lazy<Task<int>>(async () => { await Task.Delay(2000).ConfigureAwait(false); return _simpleVluae++; }); public static void Main(string[] args) { int shareValue = shardAsyncInteger.Value.Result; Console.WriteLine(shareValue); // 0 shareValue = shardAsyncInteger.Value.Result; Console.WriteLine(shareValue); // 0 shareValue = shardAsyncInteger.Value.Result; Console.WriteLine(shareValue); // 0 }
以上就是C#并发编程·典范实例读书笔记的内容,更多相关内容请关注ki4网(www.ki4.cn)!