1. Task and ThreadPool are different
1. Thread is the underlying class for creating concurrent tools, but in the previous articles we described the features and examples of Thread.Limitations can be clearly found (return values are not readily available (they must be in one scope), and when our thread finishes executing it will not perform well for the next task, it will need to be destroyed and created many times, so it is not very easy to use in multiple concurrent situations.
2. ThreadPool QueueUserWorkItem is very easy to initiate concurrent tasks, and it also resolves the above performance degradation that we need to create and destroy many times, but we are just too simple. I don't know when the thread will end, and there is no way to get the return value, which is also an embarrassing thing.
3. Tasks represent a concurrent operation through or without threads. Tasks are composable and can be concatenated using continuation. They can use thread pools to reduce startup latency and callbacks to avoid multiple threads waiting for I/O intensive operations at the same time.
2. Task (Task)
1. Task was introduced in.NET 4.0, Task was further optimized on our thread pool ThreadPool, so Task is still a thread pool thread by default, and is a background thread. When our main thread ends, other threads end as well.
2. Task creation task, similar to before
/// <summary> /// Task Use /// Task Creation is about the same /// </summary> public static void Show() { //Instance mode Task task = new Task(() => { Console.WriteLine("Delegates without return parameters"); }); //No parameter return value Task<string> task1 = new Task<string>(() => { return "I am a return value"; }); //Parametric return value Task<string> task2 = new Task<string>(x => { return "Return value -- " + x.ToString(); }, "I am an input parameter"); //Open Thread task2.Start(); //Get Return Value Result Blocks threads to get return values Console.WriteLine(task2.Result); //Create parameterless no return value threads using thread factories Task.Factory.StartNew(() => { Console.WriteLine("This is thread factory creation"); }).Start(); //Create threads with parameters and return values using thread factories Task.Factory.StartNew(x => { return "Return value -- " + x.ToString(); ; }, "I am a parameter"); //Direct Static Method Run Task.Run(() => { Console.WriteLine("Delegates without return parameters"); }); }
Explain:
1. In fact, the Task.Factory type is itself a TaskFactory, and Task.Run (introduced in.NET 4.5 and called in version 4.0) is an abbreviation of Task.Factory.StartNew, an overloaded version of the latter, which is more flexible and simple.
2. Calling the static Run method automatically creates the Task object and immediately calls Start
3. Task.Run and others start the task without calling Start, because it creates a "hot" task, on the contrary, a "cold" task is created through the Task constructor.
3. Task (Task Advancement)
1. Wait waits for the Task thread to complete before performing subsequent actions
//Create a thread to use Wait Blocking Threads Task.Run(() => { Console.WriteLine("Wait wait for Task Subsequent actions will not be performed until the thread is complete"); }).Wait();
2. WaitAll waits for the Task[] thread array to execute successfully before performing subsequent actions
//Create a container to load threads List<Task> list = new List<Task>(); for (int i = 0; i < 10; i++) { list.Add(Task.Run(() => { Console.WriteLine("WaitAll implement"); })); } Task.WaitAll(list.ToArray()); Console.WriteLine("Wait completion of enforcement");
3. WaitAny waits for any of the Task[] thread arrays to execute successfully before performing subsequent actions
//Create a container to load threads List<Task> list = new List<Task>(); for (int i = 0; i < 10; i++) { list.Add(Task.Run(() => { Console.WriteLine("WaitAny implement"); })); } Task.WaitAny(list.ToArray()); Console.WriteLine("WaitAny completion of enforcement");
4. WhenAll waits for the Task[] thread array to execute successfully before performing subsequent actions. Unlike WaitAll, he has a callback function ContinueWith
//Create a container to load threads List<Task> list = new List<Task>(); for (int i = 0; i < 10; i++) { list.Add(Task.Run(() => { Console.WriteLine("WhenAll implement"); })); } Task.WhenAll(list.ToArray()).ContinueWith(x => { return x.AsyncState; }); Console.WriteLine("WhenAll completion of enforcement");
5. WhenAny waits for any successful execution of the Task[] Thread Array to perform subsequent actions. Unlike WaitAny, he has a callback function ContinueWith
//Create a container to load threads List<Task> list = new List<Task>(); for (int i = 0; i < 10; i++) { list.Add(Task.Run(() => { Console.WriteLine("WhenAny implement"); })); } Task.WhenAny(list.ToArray()).ContinueWith(x => { return x.AsyncState; }); Console.WriteLine("WhenAny completion of enforcement"); Console.ReadLine();
4. Parallel Concurrency Control
1. Encapsulated 4.5 on the basis of Task, which is relatively simple to use. If we execute 100 tasks and only use 10 threads, we can use Parallel concurrency control
public static void Show5() { //The first method is Parallel.Invoke(() => { Console.WriteLine("I'm Thread 1"); }, () => { Console.WriteLine("I'm Thread 2"); }, () => { Console.WriteLine("I'm Thread 3"); }); //for Method to create multithreads Parallel.For(0, 5, x => { Console.WriteLine("You know it by name for Haha i=" + x); }); //ForEach Method to create multithreads Parallel.ForEach(new string[] { "0", "1", "2", "3", "4" }, x => Console.WriteLine("You know it by name ForEach Haha i=" + x)); //If we pack this one layer, we won't be able to card the main interface. Task.Run(() => { //Create Thread Options ParallelOptions parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = 3 }; //Create a concurrent thread Parallel.For(0, 5, parallelOptions, x => { Console.WriteLine("Limit number of executions"); }); }).Wait(); Console.WriteLine("**************************************"); //Break Stop Not recommended ParallelOptions parallelOptions = new ParallelOptions(); parallelOptions.MaxDegreeOfParallelism = 3; Parallel.For(0, 40, parallelOptions, (i, state) => { if (i == 20) { Console.WriteLine("thread Break,Parallel End"); state.Break();//End Parallel //return;//You must bring it with you } if (i == 2) { Console.WriteLine("thread Stop,End of current task"); state.Stop();//Current End //return;//You must bring it with you } Console.WriteLine("I am a thread i=" + i); }); }
5. Multithreaded Instances
1. Code exceptions are not unfamiliar to everyone. For example, I just wrote code that often reports=>Object undefined null. What really makes me sad, how can we handle code exceptions in our multi-threaded environment?Unlike the synchronization methods we often write, synchronization methods encounter errors that are thrown directly. If we have modern code exceptions in our multithreads, this exception will automatically pass on the Result property that calls Wait or Task <TResult>.Task exceptions are automatically caught and thrown to the caller. To ensure that all exceptions are reported, the CLR encapsulates the exceptions into the AggregateExcepiton container, which contains all the caught exceptions in the public InnerExceptions property, but will not get exceptions if our threads do not wait to end.
class Program { static void Main(string[] args) { try { Task.Run(() => { throw new Exception("error"); }).Wait(); } catch (AggregateException axe) { foreach (var item in axe.InnerExceptions) { Console.WriteLine(item.Message); } } Console.ReadKey(); } }
/// <summary> /// Multithreaded catch exception /// Multithreading swallows our exceptions because our thread execution will execute the code directly without waiting for you to catch my exceptions. /// The best thing to do in our threads is to avoid exceptions and handle them yourself. /// </summary> public static void Show() { //Create a multithreaded factory TaskFactory taskFactory = new TaskFactory(); //Create a multithreaded container List<Task> tasks = new List<Task>(); //Create delegation Action action = () => { try { string str = "sad"; int num = int.Parse(str); } catch (AggregateException ax) { Console.WriteLine("I am AggregateException I caught the exception ax:" + ax); } catch (Exception) { Console.WriteLine("I'm a thread and I've made a mistake"); } }; //This is a catch exception that we often need to do try { //Create 10 multithreads for (int i = 0; i < 10; i++) { tasks.Add(taskFactory.StartNew(action)); } Task.WaitAll(tasks.ToArray()); } catch (Exception ex) { Console.WriteLine("Abnormal"); } Console.WriteLine("I have finished executing"); }
2. Multithreaded cancel mechanism, our Task can not pause Thread().Abort() can not be well controlled externally. Thread also mentioned the shortcomings of Thread().Abort() in the previous article.If there is a problem, there is a solution.If we use a global variable control, we need to constantly monitor our variables to cancel the thread.So of course there is a corresponding method.CancellationTokenSource We can create an unflagged source and pass in our unflagged source Token when we create a thread.The Cancel() method cancels the thread, and IsCancellationRequested returns a bool value to determine if the thread has been cancelled.
/// <summary> /// Multithreaded Cancellation Mechanism Our Task Cannot pause externally Thread().Abort() Not very well controlled, our thread. /// If we use a global variable control, we need to constantly monitor our variables to cancel the thread. /// We can create an unflagged source, and we pass in our unflagged source when we create a thread Token /// Cancel() Cancel thread, IsCancellationRequested Return a bool Value to determine if the thread was cancelled /// </summary> public static void Show1() { //Create an Untagged Source CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); //Create a multithreaded factory TaskFactory taskFactory = new TaskFactory(); //Create a multithreaded container List<Task> tasks = new List<Task>(); //Create delegation Action<object> action = x => { try { //I wait 2 seconds per thread, otherwise Thread.Sleep(2000); //Determine if the thread was cancelled if (cancellationTokenSource.IsCancellationRequested) { Console.WriteLine("Abandon thread after execution"); return; } if (Convert.ToUInt32(x) == 20) { throw new Exception(string.Format("{0} Failed to execute", x)); } Console.WriteLine("I'm normal. I'm doing it"); } catch (AggregateException ax) { Console.WriteLine("I am AggregateException I caught the exception ax:" + ax); } catch (Exception ex) { //Exception All Threads Executed After Canceling cancellationTokenSource.Cancel(); Console.WriteLine("I'm a thread and I've made a mistake"); } }; //This is a catch exception that we often need to do try { //Create 10 multithreads for (int i = 0; i < 50; i++) { int k = i; tasks.Add(taskFactory.StartNew(action, k, cancellationTokenSource.Token)); } Task.WaitAll(tasks.ToArray()); } catch (Exception ex) { Console.WriteLine("Abnormal"); } Console.WriteLine("I have finished executing"); }
3. Multithreaded creates temporary variables. When we start threads, they execute faster or slower, and variables in normal loops do not work.This is when you create a temporary variable to store information and resolve not accessing a data source.
/// <summary> /// Thread Temporary Variable /// </summary> public static void Show2() { //Create a thread factory TaskFactory taskFactory = new TaskFactory(); CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); //Create a delegate Action<object> action = x => { Console.WriteLine("Incoming parameters x:" + x); }; for (int i = 0; i < 20; i++) { //The main thing is that 20 will be created k Temporary variable of int k = i; taskFactory.StartNew(action, k); } Console.ReadLine(); }
4. Multi-threaded locks. We mentioned earlier that our multi-threaded can share public resources at the same time. If we have a variable that needs to be added one, but what if we have 10 threads working on this at the same time?
public static List<int> list = new List<int>(); public static int count = 0; public static void Show3() { //Create Thread Container List<Task> tasks = new List<Task>(); for (int i = 0; i < 10000; i++) { //Add Threads tasks.Add(Task.Run(() => { list.Add(i); count++; })); } Task.WaitAll(tasks.ToArray()); Console.WriteLine("list Number of rows:" + list.Count + " count Total:" + count); Console.ReadLine(); }
The code above was originally count++ to 10,000, but when we saw the result, weren't we foolish. Why don't we say 10,000? Dogs actually ate the data?Really a kid has a lot of question marks?????
5. How can we solve this problem?Method or some today we will come to a grammatical sugar lock, what can it do?It is equivalent to a code block lock, which mainly locks an object, and when it locks the object, other threads become blocked, because when it locks the code, it also locks the access chain of the object, which is inaccessible to other threads.You must wait for the object access chain to be released before it can be accessed by a thread.When we lock code blocks with lock, we try to minimize the scope of the lock code blocks, as we lock the code so that only one thread can get the data, as long as we use the lock where we have to.
6. Places to pay attention to when using Lock
1. Lock can only lock objects of reference type.
2. Cannot lock an empty object null An object can point to null, but null does not need to be released.(Refer to: Understanding Full null).
3. lock tries not to unlock string type Although it is a reference type, string is an enjoyment mode and string type is "persisted" by CLR
This means that there is only one instance of any given string in the whole program, that is, the same object represents the text in all threads of all running application domains.Therefore, as long as a lock is placed on a string with the same content anywhere in the application process, all instances of that string in the application will be locked.Therefore, it is best to lock private or protected members that will not be persisted.
4. Lock avoids locking public types or objects that are not programmatically controlled.For example, if the instance is publicly accessible, there may be a problem with lock(this), because uncontrolled code may also lock the object.This can result in a deadlock where two or more threads wait to release the same object.Locking common data types (as opposed to objects) can also cause problems for the same reason.
/// <summary> /// Create a static object, primarily for locking blocks of code. If it is static, it will be globally locked. If you want to lock instance classes, it is better not to use static. /// </summary> private readonly static object obj = new object(); public static List<int> list = new List<int>(); public static int count = 0; /// <summary> /// lock Multithreaded locks /// Thread insecurity occurs when our threads access the same global variable, the same local variable, the same folder /// Our use lock When locking code blocks, try to minimize the scope of locking code blocks, as we lock code so that only one thread can /// Visit our code block /// </summary> public static void Show3() { //Create Thread Container List<Task> tasks = new List<Task>(); //Lock code for (int i = 0; i < 10000; i++) { //Add Threads tasks.Add(Task.Run(() => { //Lock code lock (obj) { //Only one thread accesses the resource. list.Add(i); count++; } //lock Is a grammatical sugar, which is the code below Monitor.Enter(obj); Monitor.Exit(obj); })); } Task.WaitAll(tasks.ToArray()); Console.WriteLine("list Number of rows:" + list.Count + " count Total:" + count); Console.ReadLine(); }
7. Summarize examples, two-color sphere examples.
1. Two-color balls: The number of the balls is composed of six red balls and one blue balls.Red ball number from 01-33 (no repetition) Blue ball number from 01-16 (can repeat with red ball), code I have achieved you can download Source code .Only by turning your back and forth can you make your technology grow.Next time we record the next two keywords, async and await