Welcome to learn to get rid of and deepen the inner volume
The following is the application of learning asynchronous programming
1. First, we build a winfrom project with the following interface:
2. Then write a time-consuming function:
/// <summary> ///Time consuming work /// </summary> /// <returns></returns> private string Work() { Thread.Sleep(1000); Thread.Sleep(2000); //listBox1.Items.Add("time consuming task completion"); return DateTime.Now.ToString("T") + "Enter the time-consuming function, thread ID: " + Thread.CurrentThread.ManagedThreadId; //Step 7: the child thread runs without blocking the main thread }
Here, the current thread sleep is used to simulate time-consuming work
3. Synchronization implementation method:
private void button1_Click(object sender, EventArgs e) { listBox1.Items.Add(DateTime.Now.ToString("T") + "Before calling asynchronous, the thread ID: " + Thread.CurrentThread.ManagedThreadId); //Step 1: run on the main thread and block the main thread TaskSync(); listBox1.Items.Add(DateTime.Now.ToString("T") + "After the asynchronous call, the thread ID: " + Thread.CurrentThread.ManagedThreadId); //Step 2: run in the main thread and block the main thread } /// <summary> ///Synchronization task /// </summary> private void TaskSync() { listBox1.Items.Add(DateTime.Now.ToString("T") + "Synchronization task start, thread" + Thread.CurrentThread.ManagedThreadId); var resual = Work(); listBox1.Items.Add(resual); listBox1.Items.Add(DateTime.Now.ToString("T") + "Synchronization task ends, thread" + Thread.CurrentThread.ManagedThreadId); }
Operation results:
Obviously, the above is the synchronous implementation method. When running the above code, the UI will get stuck. Because the time-consuming work runs in the main thread, the UI will be refreshed all the time, resulting in false death.
4. Then we will think that we can open a thread to run time-consuming functions, such as:
private void button4_Click(object sender, EventArgs e) { listBox1.Items.Add(DateTime.Now.ToString("T") + "Thread before independent thread" + Thread.CurrentThread.ManagedThreadId); ThreadTask(); listBox1.Items.Add(DateTime.Now.ToString("T") + "After a separate thread, the thread" + Thread.CurrentThread.ManagedThreadId); } /// <summary> ///Receive thread return value /// </summary> class ThreadParm { /// <summary> ///Receive return value /// </summary> public string resual = "Time consuming function not completed"; /// <summary> ///Thread work /// </summary> /// <returns></returns> public void WorkThread() { resual = Work(); } /// <summary> ///Time consuming work /// </summary> /// <returns></returns> private string Work() { Thread.Sleep(1000); Thread.Sleep(2000); //listBox1.Items.Add("time consuming task completion"); return DateTime.Now.ToString("T") + "Enter the time-consuming function, thread ID: " + Thread.CurrentThread.ManagedThreadId; //Step 7: the sub thread runs without blocking the main thread } } /// <summary> ///Independent thread task /// </summary> private void ThreadTask() { listBox1.Items.Add(DateTime.Now.ToString("T") + "Independent thread task start, thread" + Thread.CurrentThread.ManagedThreadId); ThreadParm arg = new ThreadParm(); Thread th = new Thread(arg.WorkThread); th.Start(); //th.Join(); var resual = arg.resual; listBox1.Items.Add(resual); listBox1.Items.Add(DateTime.Now.ToString("T") + "Independent thread task end, thread" + Thread.CurrentThread.ManagedThreadId); }
The operation results are as follows
The above is a thread running time-consuming function. The reference type (class instance) is used to receive the thread return value. The main thread is not blocked and the UI is not suspended, but the result is not what we want,
Before the time-consuming function returns, the result is directly output, that is, we do not get the processing result of the time-consuming function, and the output result is only the initialization value
resual = "the time-consuming function has not been executed";
In order to get the result, you can block the main thread with the sub thread and continue after the sub thread runs, as follows:
th.Join();
In this way, the results of time-consuming functions can be obtained and output correctly, but when the main thread is suspended, the UI is still pretending to be dead, so it does not play an optimization role.
5. The output results can be output in the sub thread (time-consuming function), so that the main thread does not have to output the results, which can output the correct results without causing the UI to fake death:
/// <summary> ///Time consuming work /// </summary> /// <returns></returns> private void Work() { Thread.Sleep(1000); Thread.Sleep(2000); listBox1.Items.Add(("T") + "Enter the time-consuming function, thread ID: " + Thread.CurrentThread.ManagedThreadId); //Step 7: the child thread runs without blocking the main thread }
If the time-consuming function is modified as above (I will omit the modification in other places) and then run, the following error will be reported:
So you would say, I'm familiar with cross thread access of controls! Don't you just add the following code during initialization:
Control.CheckForIllegalCrossThreadCalls = false;
Or it can be done by delegation.
It can really achieve the goal, but this is not elegant enough, and sometimes it is necessary to wait for the sub thread to get the return result before running the next step, so there is asynchronous waiting
6. Asynchronous implementation mode:
/// <summary> ///Asynchronous task /// </summary> /// <returns></returns> private async Task TaskAsync() { listBox1.Items.Add(DateTime.Now.ToString("T") + "Asynchronous task start, thread ID: " + Thread.CurrentThread.ManagedThreadId); //Step 3: block the main thread when the main thread is running var resual = await WorkAsync(); //Step 4: block the main thread when the main thread is running //The following steps are executed only after the WorkAsync function returns, but the waiting process does not occupy the main thread, so the main thread will not be blocked during waiting string str = DateTime.Now.ToString("T") + resual + "Current thread:" + Thread.CurrentThread.ManagedThreadId; listBox1.Items.Add(str);//Step 10: block the main thread when the main thread is running listBox1.Items.Add(DateTime.Now.ToString("T") + "Asynchronous task end, thread ID: " + Thread.CurrentThread.ManagedThreadId);//Step 11: block the main thread when the main thread is running } /// <summary> ///Asynchronous working function /// </summary> /// <returns></returns> private async Task<string> WorkAsync() { listBox1.Items.Add(DateTime.Now.ToString("T") + "Before entering the time consuming function, the thread" + Thread.CurrentThread.ManagedThreadId); //Step 5: block the main thread when the main thread is running //Ramda expression open asynchronous thread //return await Task.Run(() => //{ // Thread.Sleep(1000); // //listBox1.Items.Add("timing start:"); // Thread.Sleep(2000); // //listBox1.Items.Add("timing end"); // return "time spent:" + 30; //}); //Open asynchronous process in function mode string str = await Task.Run(Work); //Step 6: start the thread here to handle time-consuming work without blocking the main thread. The main thread returns to step 3 //The following steps are executed only after the Work function returns, but the waiting process does not occupy the main thread, so the main thread will not be blocked when waiting listBox1.Items.Add(DateTime.Now.ToString("T") + "Before going out of the asynchronous function, the thread" + Thread.CurrentThread.ManagedThreadId); //Step 9: the main thread runs and blocks the main thread return "Running time" + str; //return await Task.Run(Work); } /// <summary> ///Time consuming work /// </summary> /// <returns></returns> private string Work() { Thread.Sleep(1000); Thread.Sleep(2000); //listBox1.Items.Add("time consuming task completion"); return DateTime.Now.ToString("T") + "Enter the time-consuming function, thread ID: " + Thread.CurrentThread.ManagedThreadId; //Step 7: the child thread runs without blocking the main thread } private void button2_Click(object sender, EventArgs e) { listBox1.Items.Add(DateTime.Now.ToString("T") + "Before calling asynchronous, the thread" + Thread.CurrentThread.ManagedThreadId); //Step 1 TaskAsync();//Step 2: call the asynchronous function to block the main thread listBox1.Items.Add(DateTime.Now.ToString("T") + "After the asynchronous call, the thread" + Thread.CurrentThread.ManagedThreadId); }
The operation results are as follows:
The above can meet our needs, that is, we can not block the UI, but also wait, and return to the main thread after waiting.
Its operation logic is:
Many people on the Internet say that asynchrony starts a thread to wait for completion. From the timeline above, it does not start a new thread, but executes synchronously. Why is asynchrony? Because there is no blocking when await is executed, it directly skips waiting to execute others. When await returns, it then executes the code behind await. This series of operations are completed in the calling thread without opening the thread to wait. Therefore, if the time-consuming function does not run in a thread, it will be blocked, and the advantage of asynchrony is not fully utilized.
So, await is waiting on the main thread, so why doesn't it block the main thread? I personally think it is the use of entrustment. Let's find out the principle later!
In fact, asynchronous programming is very practical and elegant, especially combined with lamda expressions. It is extremely concise. Beginners can try more and don't avoid it.
This article is from the blog Park and written by: vv Peng For reprint, please indicate the original link: https://www.cnblogs.com/eve612/p/15778273.html
Try to escape!
Work hard!
Turn https://www.cnblogs.com/eve612/p/15778273.html