>>返回《C# 併發編程》html
同步的類型主要有兩種: 通訊和數據保護。編程
class LockClass { // 這個鎖會保護 _value。 private readonly object _mutex = new object(); private int _value; public void Increment() { lock (_mutex) { _value = _value + 1; } } }
鎖的使用,有四條重要的規則。併發
class SemaphoreSlimClass { // 這個鎖保護 _value。 private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1); private int _value; public async Task DelayAndIncrementAsync() { await _mutex.WaitAsync(); try { var oldValue = _value; await Task.Delay(TimeSpan.FromSeconds(oldValue)); _value = oldValue + 1; } finally { _mutex.Release(); } } }
規則在這裏也一樣適用異步
- 限制鎖的做用範圍。
- 文檔中寫清鎖保護的內容。
- 鎖範圍內的代碼儘可能少。
- 在控制鎖的時候毫不運行隨意的代碼
class ManualResetEventSlimClass { private readonly ManualResetEventSlim _initialized = new ManualResetEventSlim(); private int _value; public int WaitForInitialization() { _initialized.Wait(); return _value; } public void InitializeFromAnotherThread() { _value = 13; _initialized.Set(); } }
若是 ManualResetEventSlim
不能知足需求,還可考慮用 AutoResetEvent
、 CountdownEvent
或 Barrier
async
比喻:url
ManualResetEventSlim
的整個工做方法有點像人羣經過大門AutoResetEvent
事件像一個旋轉門,一次只容許一人經過。class TaskCompletionSourceClass { private readonly TaskCompletionSource<object> _initialized = new TaskCompletionSource<object>(); private int _value1; private int _value2; public async Task<int> WaitForInitializationAsync() { await _initialized.Task; return _value1 + _value2; } public void Initialize() { _value1 = 13; _value2 = 17; _initialized.TrySetResult(null); } }
信號是一種通用的通知機制code
class MaxDegreeClass { //工做流限流 IPropagatorBlock<int, int> DataflowMultiplyBy2() { var options = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 10 }; return new TransformBlock<int, int>(data => data * 2, options); } // 使用 PLINQ IEnumerable<int> ParallelMultiplyBy2(IEnumerable<int> values) { return values.AsParallel() .WithDegreeOfParallelism(10) .Select(item => item * 2); } // 使用 Parallel 類 void ParallelRotateMatrices(IEnumerable<Action<float>> matrices, float degrees) { var options = new ParallelOptions { MaxDegreeOfParallelism = 10 }; Parallel.ForEach(matrices, options, matrix => matrix.Invoke(degrees)); } //併發性異步代碼能夠用 SemaphoreSlim 來限流: async Task<string[]> DownloadUrlsAsync( IEnumerable<string> urls) { var httpClient = new HttpClient(); var semaphore = new SemaphoreSlim(10); var tasks = urls.Select(async url => { await semaphore.WaitAsync(); try { return await httpClient.GetStringAsync(url); } finally { semaphore.Release(); } }).ToArray(); return await Task.WhenAll(tasks); } }