Understanding asynchronous programming mode

Source: Internet
Author: User
Tags apm

Input and Output operations are generally much slower than other processes. In synchronous mode, threads often wait until the I/O operations are completed. When the thread does not have to wait to execute other tasks, we think this thread can execute asynchronous I/O. Asynchronous programming allows individual threads to execute some part of the code, which is called the "asynchronous programming model (APM ). In netframework, many classes support the APM mode by providing beginxxx and endxxx methods. For example, the filestream class has a read method to read data from the stream. To support APM, it also provides the beginread and endread methods. This beginxxx and endreadxxx method allows you to execute functions asynchronously. I started by explaining how to perform an asynchronous operation.

The following code uses the beginxxx and endxxx methods to allow you to run code asynchronously:

using System;using System.IO;using System.Threading;public sealed class Program {public static void Main() {byte[]  buffer = new byte[100];string filename = String.Concat(Environment.SystemDirectory, "\\ntdll.dll");FileStream  fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, 1024, FileOptions.Asynchronous);  IAsyncResult result =  fs.BeginRead(buffer, 0, buffer.Length, null, null); int numBytes = fs.EndRead(result);fs.Close();Console.WriteLine("Read {0}  Bytes:", numBytes);Console.WriteLine(BitConverter.ToString(buffer));  }}

The following is the result output:

Read 100  Bytes:4D-5A-90-00-03-00-00-00-04-00-00-00-FF-FF-00-00-B8-00-00-00-00-00-00-00-40-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-D0-00-00-00-0E-1F-BA-0E-00-B4-09-CD-21-B8-01-4C-CD-21-54-68-69-73-20-70-72-6F-67-72-61-6D-20-63-61-6E-6E-6F-74-20-62-65

The above Code uses the asynchronous APM mode to read 100 bytes from a file stream. First, you must construct a filestream object. To complete asynchronous operations, you must specify fileoptions. Asynchronous in the parameter. To synchronously read data from a file stream, you will call its read method. The prototype of this method is as follows:

public  Int32 Read(Byte[]  array, Int32 offset, Int32  count)

From the synchronous data reading function, we can see that this function will request a buffer until the data is read into the buffer and returns. This is not the right approach, because the I/O speed is unpredictable. Before I/O is completed, the calling thread will be suspended until it does not do any work, which is a waste of resources. To asynchronously read data from a file, you will call the beginread method of filestream:

IAsyncResult BeginRead(Byte[] array, Int32 offset, Int32 numBytes,AsyncCallback userCallback, object stateObject)

The beginread method is similar to the read method. The difference is that beginread will return an iasyncresult object. Let's take a look at this object after we understand the callback function callback.
Wait-completion mode allows you to call and execute other tasks asynchronously. Once these tasks are completed, you can try to end the call after other tasks are completed, and the thread will be blocked until the asynchronous call is completed. The following code uses this mode:

using System;using System.IO;using System.Threading;public sealed class Program {public static void Main() {byte[]  buffer = new byte[100];string filename = String.Concat(Environment.SystemDirectory, "\\ntdll.dll");FileStream  fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, 1024, FileOptions.Asynchronous);// make the asynchronous callfs.Read(buffer, 0, buffer.Length);  IAsyncResult result =  fs.BeginRead(buffer, 0, buffer.Length, null, null);// do some work here while you wait//Calling EndRead will block until the Async work is complete int numBytes = fs.EndRead(result);// don't forget to close the streamfs.Close();Console.WriteLine("Read {0}  Bytes:", numBytes);Console.WriteLine(BitConverter.ToString(buffer));  }}

The following is the result output:

Read 100  Bytes:20-72-75-6E-20-69-6E-20-44-4F-53-20-6D-6F-64-65-2E-0D-0D-0A-24-00-00-00-00-00-00-00-34-CB-99-AF-70-AA-F7-FC-70-AA-F7-FC-70-AA-F7-FC-57-6C-8D-FC-71-AA-F7-FC-57-6C-8A-FC-31-AA-F7-FC-57-6C-99-FC-5F-AA-F7-FC-57-6C-9A-FC-75-AB-F7-FC-57-6C-8B-FC-71-AA-F7-FC-57-6C-8F-FC-71-AA-F7-FC-52-69-63-68-70-AA-F7-FC

It is silly to call the endxxx method immediately after the beginxxx method is called, because the calling thread enters the sleep state until the operation is completed. However, if you place something between beginxxx and endxxx, it will be very difficult. We can see that the code between beginxxx and endxxx will execute other tasks while reading data, as follows:

using System;using System.IO;using System.Threading;public static class Program {   public static void Main() {      //ReadMultipleFiles(@"C:\Windows\system32\autoexec.NT", @"c:\Point.cs");      // Open the file indicating asynchronous I/O      FileStream fs = new FileStream(@"C:\windows\system32\autoexec.NT", FileMode.Open,         FileAccess.Read, FileShare.Read, 1024,         FileOptions.Asynchronous);      Byte[] data = new Byte[100];      // Initiate an asynchronous read operation against the FileStream      IAsyncResult ar = fs.BeginRead(data, 0, data.Length, null, null);      // Executing some other code here would be useful...      // Suspend this thread until the asynchronous      // operation completes and get the result      Int32 bytesRead = fs.EndRead(ar);      // No other operations to do, close the file      fs.Close();      // Now, it is OK to access the byte array and show the result.      Console.WriteLine("Number of bytes read={0}", bytesRead);      Console.WriteLine(BitConverter.ToString(data, 0, bytesRead));   }   private static void ReadMultipleFiles(params String[] pathnames) {      AsyncStreamRead[] asrs = new AsyncStreamRead[pathnames.Length];      for (Int32 n = 0; n < pathnames.Length; n++) {         // Open the file indicating asynchronous I/O         Stream stream = new FileStream(pathnames[n], FileMode.Open,            FileAccess.Read, FileShare.Read, 1024,            FileOptions.Asynchronous);         // Initiate an asynchronous read operation against the Stream         asrs[n] = new AsyncStreamRead(stream, 100);      }      // All streams have been opened and all read requests have been      // queued; they are all executing concurrently!      // Now, let's get and display the results      for (Int32 n = 0; n < asrs.Length; n++) {         Byte[] bytesRead = asrs[n].EndRead();         // Now, it is OK to access the byte array and show the result.         Console.WriteLine("Number of bytes read={0}", bytesRead.Length);         Console.WriteLine(BitConverter.ToString(bytesRead));      }   }   private sealed class AsyncStreamRead {      private Stream       m_stream;      private IAsyncResult m_ar;      private Byte[]       m_data;      public AsyncStreamRead(Stream stream, Int32 numBytes) {         m_stream = stream;         m_data = new Byte[numBytes];         // Initiate an asynchronous read operation against the Stream         m_ar = stream.BeginRead(m_data, 0, numBytes, null, null);      }      public Byte[] EndRead() {         // Suspend this thread until the asynchronous         // operation completes and get the result         Int32 numBytesRead = m_stream.EndRead(m_ar);         // No other operations to do, close the stream         m_stream.Close();         // Resize the array to save space         Array.Resize(ref m_data, numBytesRead);         // Return the bytes         return m_data;      }   }}

The following is the result output:

Number of bytes read=10040-65-63-68-6F-20-6F-66-66-0D-0A-0D-0A-52-45-4D-20-41-55-54-4F-45-58-45-43-2E-42-41-54-20-69-73-20-6E-6F-74-20-75-73-65-64-20-74-6F-20-69-6E-69-74-69-61-6C-69-7A-65-20-74-68-65-20-4D-53-2D-44-4F-53-20-65-6E-76-69-72-6F-6E-6D-65-6E-74-2E-0D-0A-52-45-4D-20-41-55-54-4F-45-58-45-43-2E-4E-54-20-69-73-20

The so-called round-robin mode is to know whether the asynchronous operation has been completed by round-robin iasyncresult. There are two examples: simple and slightly complex. Note: by calling the iscompleted attribute of the iasyncresult object returned by beginread, we can continue the work as needed until the operation is completed:

using System;using System.IO;using System.Threading;public sealed class Program {public static void Main() {byte[]  buffer = new byte[100];string filename = String.Concat(Environment.SystemDirectory, "\\ntdll.dll");FileStream  fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, 1024, FileOptions.Asynchronous);  IAsyncResult result =  fs.BeginRead(buffer, 0, buffer.Length, null, null);while (!result.IsCompleted){  // do some work here if the call isn't completed  // you know, execute a code block or somethingThread.Sleep(100);} int numBytes = fs.EndRead(result);fs.Close();Console.WriteLine("Read {0}  Bytes:", numBytes);Console.WriteLine(BitConverter.ToString(buffer));  }}

In callback mode, we need to specify a method for callback. Suppose that the asynchronous I/O request, and then your thread continues to do anything it wants to do. When the I/O request is complete, the CLR thread pool in the work project that the window queues. Finally, the threads in the thread pool will output work items and call some methods. You know that asynchronous I/O operations have been completed. Now, in this callback method, you call the endxxx method for the first time to obtain the result of the asynchronous operation, and then continue to process the result. When a method is returned, the thread in the thread pool can be traced back to the pool to serve other queued work items (or wait until one is displayed ). Even so, let's review the prototype of filestream's beginread method:

IAsyncResult BeginRead(Byte[] array, Int32 offset, Int32 numBytes, AsyncCallback userCallback, Object stateObject)

The beginread method requires two parameters: system. asynccallback and object. Asynccallback is a delegate type defined as follows:

delegate  void AsyncCallback(IAsyncResult ar);

This example references the "the CLR via C #" in Jeffrey RICHTER #":

// (code has been slightly revised)using System;using System.IO;using System.Threading;public static class Program {   // The array is static so it can be accessed by Main and ReadIsDone   private static Byte[] s_data = new Byte[100];   public static void Main() {      ReadMultipleFiles(@"C:\Windows\System32\config.NT", @"C:\point.cs");      APMCallbackUsingAnonymousMethod();      // Show the ID of the thread executing Main      Console.WriteLine("Main thread ID={0}",         Thread.CurrentThread.ManagedThreadId);      //ReadMultipleFiles(@"C:\Windows\System32\Config.NT", @"c:\Point.cs");      // Open the file indicating asynchronous I/O      FileStream fs = new FileStream(@"C:\Windows\System32\config.NT", FileMode.Open,         FileAccess.Read, FileShare.Read, 1024,         FileOptions.Asynchronous);      // Initiate an asynchronous read operation against the FileStream      // Pass the FileStream (fs) to the callback method (ReadIsDone)      fs.BeginRead(s_data, 0, s_data.Length, ReadIsDone, fs);      // Executing some other code here would be useful...      // For this demo, I'll just suspend the primary thread      Console.ReadLine();   }   private static void ReadIsDone(IAsyncResult ar) {      // Show the ID of the thread executing ReadIsDone      Console.WriteLine("ReadIsDone thread ID={0}",         Thread.CurrentThread.ManagedThreadId);      // Extract the FileStream (state) out of the IAsyncResult object      FileStream fs = (FileStream) ar.AsyncState;      // Get the result      Int32 bytesRead = fs.EndRead(ar);      // No other operations to do, close the file      fs.Close();      // Now, it is OK to access the byte array and show the result.      Console.WriteLine("Number of bytes read={0}", bytesRead);      Console.WriteLine(BitConverter.ToString(s_data, 0, bytesRead));   }   private static void APMCallbackUsingAnonymousMethod() {      // Show the ID of the thread executing Main      Console.WriteLine("Main thread ID={0}",         Thread.CurrentThread.ManagedThreadId);      // Open the file indicating asynchronous I/O      FileStream fs = new FileStream(@"C:\Windows\System32\config.NT", FileMode.Open,         FileAccess.Read, FileShare.Read, 1024,         FileOptions.Asynchronous);      Byte[] data = new Byte[100];      // Initiate an asynchronous read operation against the FileStream      // Pass the FileStream (fs) to the callback method (ReadIsDone)      fs.BeginRead(data, 0, data.Length,         delegate(IAsyncResult ar)         {            // Show the ID of the thread executing ReadIsDone            Console.WriteLine("ReadIsDone thread ID={0}",               Thread.CurrentThread.ManagedThreadId);            // Get the result            Int32 bytesRead = fs.EndRead(ar);            // No other operations to do, close the file            fs.Close();            // Now, it is OK to access the byte array and show the result.            Console.WriteLine("Number of bytes read={0}", bytesRead);            Console.WriteLine(BitConverter.ToString(data, 0, bytesRead));         }, null);      // Executing some other code here would be useful...      // For this demo, I'll just suspend the primary thread      Console.ReadLine();   }   private static void ReadMultipleFiles(params String[] pathnames) {      for (Int32 n = 0; n < pathnames.Length; n++) {         // Open the file indicating asynchronous I/O         Stream stream = new FileStream(pathnames[n], FileMode.Open,            FileAccess.Read, FileShare.Read, 1024,            FileOptions.Asynchronous);         // Initiate an asynchronous read operation against the Stream         new AsyncStreamRead(stream, 100,            delegate(Byte[] data)            {               // Process the data.               Console.WriteLine("Number of bytes read={0}", data.Length);               Console.WriteLine(BitConverter.ToString(data));            });      }      // All streams have been opened and all read requests have been      // queued; they are all executing concurrently and they will be      // processed as they complete!      // The primary thread could do other stuff here if it wants to...      // For this demo, I'll just suspend the primary thread      Console.ReadLine();   }   private delegate void StreamBytesRead(Byte[] streamData);   private sealed class AsyncStreamRead {      private Stream m_stream;      private Byte[] m_data;      StreamBytesRead m_callback;      public AsyncStreamRead(Stream stream, Int32 numBytes,         StreamBytesRead callback) {         m_stream = stream;         m_data = new Byte[numBytes];         m_callback = callback;         // Initiate an asynchronous read operation against the Stream         stream.BeginRead(m_data, 0, numBytes, ReadIsDone, null);      }      // Called when IO operation completes      private void ReadIsDone(IAsyncResult ar) {         Int32 numBytesRead = m_stream.EndRead(ar);         // No other operations to do, close the stream         m_stream.Close();         // Resize the array to save space         Array.Resize(ref m_data, numBytesRead);         // Call the application's callback method         m_callback(m_data);      }   }}

The following is the result output:

Number of bytes read=10052-45-4D-20-57-69-6E-64-6F-77-73-20-4D-53-2D-44-4F-53-20-53-74-61-72-74-75-70-20-46-69-6C-65-0D-0A-52-45-4D-0D-0A-52-45-4D-20-43-4F-4E-46-49-47-2E-53-59-53-20-76-73-20-43-4F-4E-46-49-47-2E-4E-54-0D-0A-52-45-4D-20-43-4F-4E-46-49-47-2E-53-59-53-20-69-73-20-6E-6F-74-20-75-73-65-64-20-74-6F-20-69-6E-69Number of bytes read=10075-73-69-6E-67-20-53-79-73-74-65-6D-3B-0D-0A-0D-0A-70-75-62-6C-69-63-20-73-74-61-74-69-63-20-63-6C-61-73-73-20-50-72-6F-67-72-61-6D-20-7B-0D-0A-20-20-20-70-75-62-6C-69-63-20-73-74-61-74-69-63-20-76-6F-69-64-20-4D-61-69-6E-28-73-74-72-69-6E-67-5B-5D-20-61-72-67-73-29-20-7B-0D-0A-20-20-20-20-20-20-56Main thread ID=1ReadIsDone thread ID=4Number of bytes read=10052-45-4D-20-57-69-6E-64-6F-77-73-20-4D-53-2D-44-4F-53-20-53-74-61-72-74-75-70-20-46-69-6C-65-0D-0A-52-45-4D-0D-0A-52-45-4D-20-43-4F-4E-46-49-47-2E-53-59-53-20-76-73-20-43-4F-4E-46-49-47-2E-4E-54-0D-0A-52-45-4D-20-43-4F-4E-46-49-47-2E-53-59-53-20-69-73-20-6E-6F-74-20-75-73-65-64-20-74-6F-20-69-6E-69

The following describes how to use the thread pool. In. net, we need to start with the following four steps:
1. Create a function without any parameters and without any return values
2. Create a threadstart delegate and specify the function in step 1.
3. Create a thread object and specify the threadstart delegate in step 2.
4. Call thread. Start to execute a new thread.
The following is an example:

The following is an example: using system; using system. threading; public class app {public static void main () {threadstart task = new threadstart (basicwork); thread mythread = new thread (task); mythread. start ();} static void basicwork () {console. writeline ("thread: {0}", thread. currentthread. managedthreadid );}}

In real-world threads, We need to transmit information to various threads. Note that the preceding example uses the threadstart delegate without any parameters. OK. Therefore, we need to pass the data to the thread. What should I do? You can use a new delegate called parameterizedthreadstart. The method signature specified by this delegate uses an object-type parameter and no response is returned. The following is a sample code that passes data to a thread:

using System;using System.Threading;public class App {public static void Main() {ParameterizedThreadStart task = new ParameterizedThreadStart(WorkWithParameter;Thread myThread = new Thread(task);myThread.Start("Whatcha doin?");Thread newThread = new Thread(task);newThread.Start("Nuthin much");}static void WorkWithParameter(object o) {    string info = (string) o; for (int x = 0; x < 10; ++x)  {   Console.WriteLine("{0}: {1}", info, Thread.CurrentThread.ManagedThreadId);   Thread.Sleep(10);   }  }}

The following is the result output:

Whatcha doin?: 3Nuthin much: 4Whatcha doin?: 3Nuthin much: 4Whatcha doin?: 3Nuthin much: 4Whatcha doin?: 3Nuthin much: 4Whatcha doin?: 3Nuthin much: 4Whatcha doin?: 3Nuthin much: 4Whatcha doin?: 3Nuthin much: 4. . . . . . .

In many cases, there is no need to create your own thread, and many professional documents do not even recommend this. . Net threads support built-in thread pools. In many cases, you may think that you must create your own threads. Recall the static method used in the previous example to pass data to a thread:

static void WorkWithParameter(object o) {    string info = (string) o; for (int x = 0; x < 10; ++x)  {   Console.WriteLine("{0}: {1}", info, Thread.CurrentThread.ManagedThreadId);   Thread.Sleep(10);   }  }

We can use the queueuserworkitem method of the thread pool to replace the functions completed by the above Code:

WaitCallback workItem = new WaitCallback(WorkWithParameter); If (!ThreadPool.QueueUserWorkItem(workItem, “ThreadPooled”)) {  Console.WriteLine(“Could not queue item”);}

 

 

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.