線程同步

>>返回《C# 併發編程》html

同步的類型主要有兩種: 通訊數據保護編程

1. 阻塞鎖

class LockClass
{
    // 這個鎖會保護 _value。
    private readonly object _mutex = new object();
    private int _value;
    public void Increment()
    {
        lock (_mutex)
        {
            _value = _value + 1;
        }
    }
}

鎖的使用,有四條重要的規則。併發

  • 限制鎖的做用範圍。
  • 文檔中寫清鎖保護的內容。
  • 鎖範圍內的代碼儘可能少。
  • 在控制鎖的時候毫不運行隨意的代碼

2. 異步鎖

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();
        }
    }
}

規則在這裏也一樣適用異步

  • 限制鎖的做用範圍。
  • 文檔中寫清鎖保護的內容。
  • 鎖範圍內的代碼儘可能少。
  • 在控制鎖的時候毫不運行隨意的代碼

3. 阻塞信號

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 不能知足需求,還可考慮用 AutoResetEventCountdownEventBarrierasync

比喻:url

  • ManualResetEventSlim 的整個工做方法有點像人羣經過大門
  • AutoResetEvent 事件像一個旋轉門,一次只容許一人經過。

4. 異步信號

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

  • 若是這個「信號」是一個用來在代碼段之間發送數據的消息,那就考慮使用生產者/消費者隊列
  • 不要讓通用的信號只是用來協調對共享數據的訪問,那種狀況下,可以使用鎖。

5. 限流

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);
    }
}
相關文章
相關標籤/搜索