Home  >  Article  >  Backend Development  >  C# Concurrent Programming·Classic Examples Reading Notes

C# Concurrent Programming·Classic Examples Reading Notes

黄舟
黄舟Original
2017-02-06 16:43:461460browse

Preface

Recently I was reading the book "C# Concurrent Programming·Classic Examples". This is not a theoretical book, but it is a book that mainly talks about how to better use the current C#.NET A book of these APIs is provided for us. Most of the books are examples, which are often used in daily development.

I quite agree with some of the views in the book. For example, the author said that most books currently put content about concurrent multi-threading at the end, but lack an introductory guide and reference for concurrent programming.

Another point of view is that the vast majority of domestic technical personnel believe that the lower the level of technology, the more powerful it is, while those who do upper-level applications are "code farmers". The author opposes this view. In fact, we can make good use of existing Library is also a kind of ability. Although understanding the basic knowledge is still helpful in daily life, it is better to learn from higher-level abstract concepts.

Asynchronous basics

Task suspension and hibernation

To pause or hibernate tasks asynchronously, you can use Task.Delay();

static async Task<T> DelayResult<T>(T result, TimeSpan delay) {
    await Task.Delay(delay);
    return result;
}

Asynchronous retry mechanism

A simple exponential backoff strategy, the retry time will increase gradually. This strategy is generally used when accessing Web services.

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

Report progress

In asynchronous operations, it is often necessary to display the progress of the operation, and you can use IProcess and Process.

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

Wait for a group of tasks

Execute several tasks at the same time, wait for them all to complete

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

Wait for any one task to complete

Execute several tasks, only Requires a response to the completion of one of these. It is mainly used to perform multiple independent attempts on an operation. As long as one of the attempts is completed, the task is completed.

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

Collections

Immutable stacks and queues

Require a stack and queue that will not be modified frequently and can be safely accessed by multiple threads. Their API is very similar to Stack and Queue. In terms of performance, immutable stacks (LIFO) and queues (FIFO) have the same time complexity as standard stacks and queues. But in simple cases where frequent modifications are required, standard stacks and queues are faster.

In terms of internal implementation, when an object is overwritten (reassigned), the immutable collection returns a modified collection, and the original collection reference does not change. That is to say, if another If a variable refers to the same object, it (other variables) will not change.

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

In fact, the two stacks share the memory of storing 11. This implementation is very efficient, and each instance is thread-safe.

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

Immutable lists and collections

ImmutableList

Time complexity

C# Concurrent Programming·Classic Examples Reading Notes

Sometimes you need a data structure that supports indexing, is not modified frequently, and can be safely accessed by multiple threads.

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 can be indexed, but pay attention to performance issues and cannot use it to simply replace List. Its internal implementation uses a binary tree to organize data. This is done to allow memory to be shared between different instances.

ImmutableHashSet

Sometimes you need such a data structure: it does not need to store duplicate content, is not modified frequently, and can be safely accessed by multiple threads. Time complexity 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 顺序不定

Thread-safe dictionary

A thread-safe key-value pair collection, multiple threads can still maintain synchronization when reading and writing.

ConcurrentDictionary

Using a mixture of fine-grained locking and lock-free techniques, it is one of the most practical collection types.

var dictionary = new ConcurrentDictionary<int, string>();
dictionary.AddOrUpdate(0, key => "Zero", (key, oldValue) => "Zero");

If multiple threads read and write a shared collection, ConcurrentDictionary is most appropriate. If it will not be modified frequently, it is more suitable to use ImmutableDictionary.

It is most suitable for situations where data needs to be shared, that is, multiple threads share a collection. If some threads only add elements and some threads only remove elements, it is best to use a producer/consumer collection ( BlockingCollection).

Initialize shared resources

The program uses a value in multiple places and initializes it when accessing it for the first time.

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
}

The above is the content of C# Concurrent Programming·Classic Examples reading notes. For more related content, please pay attention to the PHP Chinese website (www.php.cn)!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn