[C # advanced series] 27 I/O-restricted asynchronous operations,

Source: Internet
Author: User

[C # advanced series] 27 I/O-restricted asynchronous operations,

The previous chapter describes how to use thread pools, tasks, parallel functions, and PLINQ to restrict asynchronous operations based on thread pools.

This chapter describes how to asynchronously execute I/O restrictions and allow tasks to be handed over to hardware devices for processing without occupying threads and CPU resources.

However, the thread pool still plays an important role, because the results of various I/O operations still need to be processed by the thread pool thread.

How to perform synchronous I/O operations in Windows

Now that asynchronous I/O operations are involved, you can first check how the synchronization operations are performed.

For example, to operate a file on a hard disk, open the disk file by constructing a FileStream object, and then call the Read method to Read data from the file.

When the Read method is called, the thread changes from the managed code to the local/user mode code, and the Read internally calls the Win32 ReadFile function.

ReadFile allocates a small data structure called the I/O Request Packet (IRP ).

After the IRP structure is initialized, the following content is contained: file handle, the offset in the file (Reading bytes from this position), the address of a Byte [] array, the number of bytes to be transmitted and other conventional content.

Then, the ReadFile function converts the thread code from the local/user mode to the local/kernel mode code, such as passing IRP in the kernel to call the Windows kernel. According to the device handle in the IRP, the Windows Kernel knows the hardware device to which the I/O operation is sent.

Therefore, Windows sends IRP to the IRP queue of the appropriate device driver. Each device driver maintains its own IRP queue, which contains the I/O requests sent by all processes running on the machine.

When an IRP packet arrives, the device driver transmits the IRP information to the circuit board installed on the physical hardware device. Now, the hardware device performs the requested I/O operation.

During the hardware I/O operation, the thread that sends an I/O Request has nothing to do, so Windows changes the thread to sleep to prevent it from wasting CPU time. (However, memory is still wasted because its user mode stack, Kernel Mode stack, thread environment block, and other data structures are still in the memory, and there is nothing to access the memory ).

The hardware device completes the I/O operation, and then the Windows wake up the thread and schedule it to a CPU so that it returns the user mode from the kernel mode and then to the managed code. The Read method of FileStream returns an Int32, indicating the number of bytes Read from the file, so that we can know how many bytes can be retrieved in the Byte [] passed to the Read.

For Web servers, this will be a pitfall. As you can imagine, if many users request the server to obtain information about a file or database, the thread is blocked during the retrieval and waits for the response, a lot of threads will be created. If the number of users is large enough, the server is not enough.

When the information is obtained and a large number of threads are awakened, a large number of threads exist at this time, and the CPU kernel is generally not much, so the context is frequently switched, which further damages the performance.

How does one perform asynchronous I/O operations in Windows?

The performance of synchronous I/O operations in some scenarios requires asynchronous operations.

In this example, a FileStream is constructed to read files. However, a FileOptions. Asynchronous mark is passed, indicating that Windows wants to read and write files asynchronously.

In addition, instead of calling Read, ReadAsync is used to Read data.

ReadAsync internally allocates a Task <Int> to indicate the code used to complete the read operation.

Then, ReadAsync calls the Win32 ReadFile function.

ReadFile allocates IRP, initializes it like the previous synchronization operation, and passes it to the windows kernel.

The Windows Kernel puts IRP in the driver queue, but the thread is no longer blocked and can return to your code. (This is the benefit of Asynchronization)

Therefore, the thread can return immediately from the ReadAsync call. Of course, at this time, the IRP has not been properly processed, so you cannot access the bytes in the passed Byte [] in the code after ReadAsync.

The Task <Int> object created internally before ReadAsync is returned to the user.

You can call ContinueWith on this object to register the callback method executed when the task is completed, and then process data in the callback function. Of course, you can also use the asynchronous function of C # To simplify code and write code in sequence (like executing synchronous I/O ).

After the hardware device processes the IRP, it will put it in the CLR thread pool queue. In the future, a thread pool thread will extract the completed IRP and/into the task code, finally, either an exception is set (if an error occurs) or a result is returned (in this example, an Int32 indicating the number of successfully read bytes)

In this way, the Task object knows when the operation is completed, and the code can start to run and securely access data in Byte.

In this way, the thread is not blocked so that resources are not excessively wasted and the I/O efficiency is improved.

C # asynchronous Functions

I have never used asynchronous functions in my WEB writing experience, but I used them before when I played an event Unity3D.

Actually in the previous chapterScheduled computing restrictionsThe Section has already been used. paste the example:

Static void Main (string [] args) {asyncDoSomething (); Console. read ();} private static async void asyncDoSomething () {while (true) {Console. writeLine ("time is {0}", DateTime. now); // The await Task is delayed for two seconds without blocking the thread. delay (2000); // await allows the thread to return // after 2 seconds, a thread will intervene and continue to loop after await }}

The asyncDoSomething function is an asynchronous function.

It has an obvious sign that async declares it.

In fact, the asynchronous function uses tasks to implement Asynchronization, and uses a concept not mentioned before: state machine.

Asynchronous functions, as the name implies, will be executed asynchronously. In addition, operation A after await is also executed asynchronously. After operation A is executed, it will continue to execute the statements following the await statement.

It is written as a normal function. In fact, it uses the Task ContinueWith to run the restore state machine method. After the Task. Delay (2000) thread is executed, another thread calls the code after await.

Pay attention to the following points when using asynchronous functions:

  • The Main function of the program cannot be used as an asynchronous function. In addition, the constructors, attributes, and event accessors methods cannot be used.
  • Asynchronous functions cannot have out and ref parameters.
  • The await operator cannot be used in catch, finally, or unsafe blocks.
  • You cannot obtain a lock that supports thread ownership or recursion before the await operator and release it after the await operator. This is because the code before await is executed by one thread, and the subsequent code is executed by another thread.
  • In a query expression, the await operator can only be used in the first set expression of the initial from clause, or in the Set expression of the join clause.

The return type of asynchronous functions is generally Task or Task. They indicate that the state machine of the function is completed. (However, you can also return void as in the preceding example)

In fact, if the last return value of the asynchronous function is an int value, the return type of the asynchronous function should be Task <int>.

Generally, asynchronous functions add the Async suffix after the method name according to the standard requirements. Many types of I/O operations support the Async method.

In earlier versions, a programming model used the BeginXxx/EndXxx method and the IAsyncResult interface.

There is also an event-based programming model that provides the XxxAsync method (the Task object is not returned because all events are void)

Now both programming models are outdated. We recommend that you use a new programming model for functions ending with Async. (However, there are still some classes because Microsoft does not have time to update, so these classes only have the BeginXxx method)

For classes with only BeginXxx and EndXxx programming models, you can use Task. factory. the FromAsync method transmits BeginXxx and EndXxx as parameters to FromAsync, and then await Task can be performed. factory. fromAsync (BeginXxx, EndXxx, null) method, with the new programming model.

Application and thread processing model

. NET supports several different application models, and each model may introduce its own thread processing model.

The console applications and Windows Services (actually console applications, but the console is not visible) do not introduce any thread processing model.

The GUI application introduces a thread processing model. In this model, the UI element can only be updated by the thread that created it.

In GUI threads, an asynchronous operation is often generated to prevent the GUI thread from blocking and stop responding to user input. However, when asynchronous operations are completed, a thread pool thread completes the Task object and restores the state machine.

However, when the thread pool thread updates the UI element, it throws an exception. Therefore, the thread pool thread can only tell the GUI thread to update the UI element in some way.

However, FCL defines a SynchronizationContext class to solve this problem. Simply put, such objects connect the application model and the thread processing model.

Developers usually do not need to understand this class. When waiting for a Task, they will get the SynchronizationContext object of the calling thread. After the thread pool completes the Task, the SynchronizationContext object will be used, make sure that the correct thread processing model is used for the application model.

Therefore, when the GUI thread waits for a Task, the code behind the await operator must be executed on the GUI thread so that the code can be correctly executed.

A Task provides a ConfigureAwait method. Passing true to a Task is equivalent to not calling a method. If false is passed, the await operator does not query the SynchronizationContext object of the call thread. When the thread pool ends the Task, the code behind the await operator is executed through the thread pool thread.

Perform I/O operations Asynchronously

Although I/O operations in asynchronous mode are introduced earlier, in fact, those operations are simulating asynchronous operations using another thread internally. This extra thread will also affect the performance.

If you specify the FileOptions. Asynchronous flag when creating a FileStream object, it indicates synchronous or Asynchronous communication.

In this mode, the Read method is used internally to simulate synchronous implementation. (In fact, if Asynchronous is specified, ReadAsync is used. If synchronous, Read is used to obtain the best performance)

 

PS:

In fact, the amount of gold in this chapter is much more than what I have written, and it cannot be fully written with limited capabilities. (I am a little confused about the large amount of information. After completing this round, I have to look back at multithreading)

Especially in the state machine of asynchronous functions, this book describes in detail, but I have not written too much.

The author uses a large piece of code to explain the problem, but I am too lazy to copy it.

However, I believe that the central idea is still extracted. In fact, the task is used, and the function is equivalent to the Code ContinueWith after await.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.