Asynchronous and multithreaded Thread

When you first touch threads, it feels amazing. Although it is not very clear, it feels very compelling.

Refer to some articles written by big guys:

https://www.cnblogs.com/yilezhu/p/10555849.html I still like the articles written by this big man.

https://www.cnblogs.com/mushroom/p/4575417.html

 

Multithreading is a very important part of. NET development. Many developers have little or no fear of multithreading. Therefore, when writing code, they do not consider the multithreading scenario.

What is a process?

Computer concept, the integration of computer resources occupied by programs running on servers, is a virtual concept.

When a program starts to run, it is a process, which includes the memory and system resources used by the running program and program.

A process is composed of multiple threads.

What is thread?

Computer concept, the smallest unit of process response operation, including CPU, memory, network, and hard disk IO.

Threads are a flow of execution in a program. Each thread has its own special register (stack pointer, program counter, etc.), but the code area is shared, that is, different threads can execute the same function.

 

What is multithreading?

Computer concept, a process has multiple threads running at the same time.

Multithreading means that a program contains multiple execution streams, that is, multiple different threads can be run simultaneously in a program to perform different tasks, that is to say, it allows a single program to create multiple parallel execution threads to complete their respective tasks.

  

A process contains many threads; threads belong to a process, and the process destroys the thread.

Handle: Actually, it's a long number. It's the operating system that represents the application.

Multithreading in C#?

Thread class is an encapsulation of threaded objects in C# language.

Why multithreading?

1. Multiple CPU cores can work in parallel and multiple analog threads

Four-core and eight-thread, where the thread value is the analog core

2. CPU slicing, 1S processing capacity is divided into 1000 copies, the operating system is scheduled to respond to different tasks. From a macro perspective, it feels like multiple tasks are executed concurrently; from a micro perspective, a physical CPU can only serve one task at the same time.

Synchronization method:

Initiate the call, and then proceed to the next line after it has been completed; it is very consistent with the development thinking and is implemented in an orderly manner.

Simply put, it means inviting people to dinner sincerely, such as inviting bingle to eat, but bingle will be busy for a while, then wait for the completion of bingle to eat together.

Asynchronous method:

Initiate the call, do not wait to complete, go directly to the next line, start a new thread to complete the calculation of the method.

Simply put, it's a polite invitation to dinner, such as inviting bingle to have dinner, but if bingle is busy for a while, you should be busy. I'll go to dinner first, and you'll be busy to eat yourself.

Synchronization method code:

 private void btnSync_Click(object sender, EventArgs e)
 {
     Console.WriteLine($"****************btnSync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
     int l = 3;
     int m = 4;
     int n = l + m;
     for (int i = 0; i < 5; i++)
     {
         string name = string.Format($"btnSync_Click_{i}");
         this.DoSomethingLong(name);
     }
     Console.WriteLine($"****************btnSync_Click   End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

 }

 /// <summary>
 /// A more time-consuming and resource-consuming private approach
 /// </summary>
 /// <param name="name"></param>
 private void DoSomethingLong(string name)
 {
     Console.WriteLine($"****************DoSomethingLong Start  {name}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
     long lResult = 0;
     for (int i = 0; i < 1_000_000_000; i++)
     {
         lResult += i;
     }
     //Thread.Sleep(2000);

     Console.WriteLine($"****************DoSomethingLong   End  {name}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
 }

This is the result of the call.

 

During this period, the interface was stuck and could not be dragged.

The code of the asynchronous method:

private void btnAsync_Click(object sender, EventArgs e)
{
    Console.WriteLine($"****************btnAsync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
    Action<string> action = this.DoSomethingLong;

    //action.Invoke("btnAsync_Click_1");
    //action("btnAsync_Click_1");

    //Delegate the required parameters + 2 asynchronous parameters
    //action.BeginInvoke("btnAsync_Click_1", null, null);

    for (int i = 0; i < 5; i++)
    {
        string name = string.Format($"btnAsync_Click_{i}");
        action.BeginInvoke(name, null, null);
    }

    Console.WriteLine($"****************btnAsync_Click End   {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
}

The result after the call is as follows:

During this period, the interface is not stuck and can be dragged at will. It's just that the interface is still executed by the main thread, in which sub-threads are opened to execute other methods.

The difference between synchronous method and asynchronous method:

Synchronization method:

The main thread (UI thread) is busy calculating and has no time to care about. The interface is blocked.

Asynchronous method:

The main thread is idle, the computing task is handed over to the sub-threads to complete, improve the user experience, winform clicks a few buttons, so as not to get stuck; web development, as well as the need, send a short message notification, or download an Excel, are handed to the asynchronous threads to do.

The synchronization method is slow because there is only one thread computing, and the asynchronous method is fast because there are multiple threads computing concurrently. Multithreading is actually about exchanging resources for performance.

When to use multithreading?

1. An order form is time-consuming. Can you optimize performance with multi-threading?

The answer is no, because it's an operation and it's not parallel.

2. Need to query database/call interface/read hard disk file/do data calculation, can we use multi-threading to optimize performance?

This is OK. Because multiple tasks can be parallel, but multi-threading is not the more the better, because resources are limited, and scheduling is lossy, multi-threading as far as possible to avoid using.

Let's look at the order of execution after the above call:

Synchronized methods proceed in an orderly manner, but asynchronous methods start out in an disorderly manner. Since thread resources are requested from the operating system and are determined by the scheduling decision of the operating system, the startup is out of order. The same task uses one thread, and the execution time is uncertain, which is caused by CPU fragmentation.

Be careful with multithreading. Many things are not taken for granted, especially when the time required for multithreading is orderly (async await can solve this problem). Can you control the order by delaying a little startup? Or predict the end order? These are unreliable. Even though the order of execution and expectation is always the same after a large number of tests, this always happens as long as the probability is different.

Parallel: Parallel between multiple cores.

Concurrent: Concurrent CPU fragmentation.

Callback: The subsequent action is passed in through the callback parameter, and the subthread calls the callback delegate after completing the calculation.

Code:

 private void btnAsyncAdvanced_Click(object sender, EventArgs e)
 {
     Console.WriteLine($"****************btnAsyncAdvanced_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

     Action<string> action = this.DoSomethingLong;
     AsyncCallback callback = ar =>
     {
         Console.WriteLine($"btnAsyncAdvanced_Click The calculation is successful... ThreadId is{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
     };
     action.BeginInvoke("btnAsyncAdvanced_Click", callback, null);
}

Implementation results:

Callback Reference:

Code:

private void btnAsyncAdvanced_Click(object sender, EventArgs e)
{
    Console.WriteLine($"****************btnAsyncAdvanced_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

    Action<string> action = this.DoSomethingLong;
    //1 Callback: Pass in the subsequent action through the callback parameter, and after the subthread completes the calculation, invoke the callback delegate
    IAsyncResult asyncResult = null;//Description of asynchronous invocation operations
    AsyncCallback callback = ar =>
    {
        Console.WriteLine($"{object.ReferenceEquals(ar, asyncResult)}");
        Console.WriteLine($"btnAsyncAdvanced_Click The calculation is successful...{ar.AsyncState}. {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
    };
    asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", callback, "bingle");

Look at the result. The parameter bingle is passed in.

Waiting through IsComplate, Card Interface - The main thread is waiting, waiting while prompting

////2 adopt IsComplate Waiting, card interface--The main thread is waiting, waiting and prompting
////( Thread.Sleep(200);The position has changed, a sentence is missing 99.9999)
int i = 0;
while (!asyncResult.IsCompleted)
{
    if (i < 9)
    {
        Console.WriteLine($"bingle{++i * 10}%....");
    }
    else
    {
        Console.WriteLine($"bingle99.999999%....");
    }
    Thread.Sleep(200);
}
Console.WriteLine("Already completed!");

WaitOne Wait, Instant Wait, Time-limited Wait

asyncResult.AsyncWaitHandle.WaitOne();//Waiting directly for the task to be completed
asyncResult.AsyncWaitHandle.WaitOne(-1);//Waiting for the task to be completed
asyncResult.AsyncWaitHandle.WaitOne(1000);//Wait up to 1000 ms,Overtime will not wait.
//4 EndInvoke Instant wait, And you can get the return value of the delegate. An asynchronous operation can only End Once
action.EndInvoke(asyncResult);//Waiting for the end of an asynchronous call operation

Class Thread

As mentioned above, Thread is a C # encapsulation of threaded objects.

Thread:C Encapsulation of Thread Objects
Many of the Thread methods are powerful, but they are also too powerful and unrestricted.

ParameterizedThreadStart method = o => this.DoSomethingLong("btnThread_Click");
Thread thread = new Thread(method);
thread.Start("123");//Open threads to execute delegated content
Here's Obsell's api
 // thread.Suspend();//pause
 // thread.Resume(); // Recovery is really not necessary, pause is not necessarily immediately suspended; making thread operations too complex
 //thread.Abort();
 //// Threads are computer resources. Programs that want to stop threads can only notify the operating system (threads throw exceptions).
 //// There will be delays/not necessarily stops.

Threads wait, as follows:

while (thread.ThreadState != ThreadState.Stopped)
{
    Thread.Sleep(200);//Current thread rest 200 ms
}
//2 Join wait for
thread.Join();//The thread that runs this code, waits thread Completion
thread.Join(1000);//Wait up to 1000 ms

thread.Priority = ThreadPriority.Highest; highest priority, limited execution, but not priority completion. It means that in extreme cases, there are accidents that can not be used to control the execution sequence of threads.

thread.IsBackground = false;//The default is false Front-end threads, processes closed, threads need to be calculated before exiting
//thread.IsBackground = true;//Close the process and exit the thread

Based on Thread, a callback can be encapsulated: the promoter thread executes action A - - no blocking - - after execution of action A, the subthread executes action B.

Code:

private void ThreadWithCallBack(ThreadStart threadStart, Action actionCallback)
{
    //Thread thread = new Thread(threadStart);
    //thread.Start();
    //thread.Join();//Wrong, because the method is blocked.
    //actionCallback.Invoke();

    //That's the wrong way. You should use it first. threadStart,Call again callback

    ThreadStart method = new ThreadStart(() =>
    {
        threadStart.Invoke();
        actionCallback.Invoke();
    });
    new Thread(method).Start();
}

Call the test:

 ThreadStart threadStart = () => this.DoSomethingLong("btnThread_Click");
 Action actionCallBack = () =>
   {
       Thread.Sleep(2000);
       Console.WriteLine($"This is Calllback {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
   };
 this.ThreadWithCallBack(threadStart, actionCallBack);

Encapsulating a method with a return value based on Thread:

private Func<T> ThreadWithReturn<T>(Func<T> func)
{
    T t = default(T);
    ThreadStart threadStart = new ThreadStart(() =>
    {
        t = func.Invoke();
    });
    Thread thread = new Thread(threadStart);
    thread.Start();

    return new Func<T>(() =>
    {
        thread.Join();
        //thread.ThreadState
        return t;
    });
}

Call:

 Func<int> func = () =>
     {
         Thread.Sleep(5000);
         return DateTime.Now.Year;
     };
 Func<int> funcThread = this.ThreadWithReturn(func);//Non blocking
 Console.WriteLine("do something else/////");
 Console.WriteLine("do something else/////");
 Console.WriteLine("do something else/////");
 Console.WriteLine("do something else/////");
 Console.WriteLine("do something else/////");

 int iResult = funcThread.Invoke();//block
 Console.WriteLine(iResult);

 

 

funcThread.Invoke() at the time of the call, where a blocking occurred. Neither blocking nor calculating results? Impossible!

Thread pool:

Thread, with its many functions, is not good. It's like giving a hot weapon to a 4-year-old child, but it will cause more harm, and it has no control over the number of threads.

In. NET Framework 2.0, a thread pool appeared. If an object is expensive to create and destroy and can be reused repeatedly, a pool is needed. Save multiple such objects, get them from the pool when needed, and then put them back into the pool (hedonic mode) without destroying them. This can save resources and improve performance; in addition, it can control the total number and prevent abuse. ThreadPool threads are background threads.

The simplest use of ThreadPool is:

ThreadPool.QueueUserWorkItem(o => this.DoSomethingLong("btnThreadPool_Click1"));
ThreadPool.QueueUserWorkItem(o => this.DoSomethingLong("btnThreadPool_Click2"), "bingle");
 //wait for
 ManualResetEvent mre = new ManualResetEvent(false);
 //false---Close---Set open---true---WaitOne Can pass
 //true---open--ReSet Close---false--WaitOne Just wait
 ThreadPool.QueueUserWorkItem(o =>
 {
     this.DoSomethingLong("btnThreadPool_Click1");
     mre.Set();
 });
 Console.WriteLine("Do Something else...");
 Console.WriteLine("Do Something else...");
 Console.WriteLine("Do Something else...");

 mre.WaitOne();
 Console.WriteLine("The task has been completed...");

Implementation results:

 

 

Do not block threads in the thread pool:

ThreadPool.SetMaxThreads(8, 8);
ManualResetEvent mre = new ManualResetEvent(false);
for (int i = 0; i < 10; i++)
{
    int k = i;
    ThreadPool.QueueUserWorkItem(t =>
    {
        Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId.ToString("00")} show {k}");
        if (k == 9)
        {
            mre.Set();
        }
        else
        {
            mre.WaitOne();
        }
    });
}
if (mre.WaitOne())
{
    Console.WriteLine("All the tasks have been successfully carried out! ____________");
}

 

The program card is here, because there are only eight threads in the thread pool, and now there are eight threads waiting, which forms a deadlock, and the program is stuck here. So don't block threads in the thread pool.

 

It's a bit too long. The following note introduces Task from. NET Framework 3.0, as well as async and await.

Tags: C# network Web Development Excel Database

Posted on Fri, 20 Sep 2019 02:45:46 -0700 by devain