• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
我就是停不下来
业精于勤荒于嬉,行成于思毁于随
博客园    首页    新随笔    联系   管理    订阅  订阅

异步编程(2)

APM支持三种聚集的技巧:等待直到完成,轮询和方法回调,下面追一介绍这几种技巧:

1.等待直至完成

using System;
using System.IO;
using System.Threading;
public static class Program ...{
public static void Main() ...{
FileStream fs 
= new FileStream(@"C:Boot.ini", FileMode.Open,
FileAccess.Read, FileShare.Read, 
1024,
FileOptions.Asynchronous);
Byte[] data 
= new Byte[100];

//异步读取文件,所有的BeginXXX方法都会返回IAsyncResult类型的变量
IAsyncResult ar = fs.BeginRead(data, 0, data.Length, null, null);

//执行一些其他操作

Int32 bytesRead 
= fs.EndRead(ar);
fs.Close();
Console.WriteLine(
"Number of bytes read={0}", bytesRead);
Console.WriteLine(BitConverter.ToString(data, 
0, bytesRead));
}

}


//输出
5B-62-6F-6F-74-20-6C-6F-61-64-65-72-5D-0D-0A-74-69-6D-65-6F-
75-74-3D-33-30-0D-0A-64-65-66-61-75-6C-74-3D-6D-75-6C-74-69-
28-30-29-64-69-73-6B-28-30-29-72-64-69-73-6B-28-30-29-70-61-
72-74-69-74-69-6F-6E-28-31-29-5C-57-49-4E-44-4F-57-53-0D-0A-
5B
-6F-70-65-72-61-74-69-6E-67-20-73-79-73-74-65-6D-73-5D-0D

 注意上面的调用,如果执行到ENDXXX,文件还没有读取完成,那么将会挂起调用线程,直至方法返回结果。下面看一下一个改进的版本,这个版本可以从多个文件,套接字,甚至串口中读取字节:

private static void ReadMultipieFiles(params String[] pathnames) ...{

AsyncStreamRead[] asrs 
= new AsyncStreamRead[pathnames.Length];

for (Int32 n = 0; n < pathnames.Length; n++) ...{
Stream stream 
= new FileStream(pathnames[n], FileMode.Open,FileAccess.Read, FileShare.Read, 1024,FileOptions.Asynchronous);
asrs[n] 
= new AsyncStreamRead(stream, 100);
}


for (Int32 n = 0; n < asrs.Length; n++) ...{
Byte[] bytesRead 
= asrs[n].EndRead() ;
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];
m_ar 
= stream.BeginRead(m_data, 0, numBytes, null, null);
}


public Byte[] EndRead() ...{
Int32 numBytesRead 
= m_stream.EndRead(m_ar);
m_stream.Close();
Array.Resize(
ref m_data, numBytesRead);
return m_data;
}

}

上面的方法还有一个低效的地方就是在第二个循环,我们要按顺序调用ENDXXX方法,但是每个文件的大小不一样,那么他的读取完成时间就会不同,如果前面有一个非常大的文件,而后面的文件比较小,我们在等待大文件读取完毕的时候,他后面的文件已经读取完了,但是我们还要等待这个大文件读取完了才能显示后面的文件内容。

2.轮询

public static void PollingWithIsCompleted() ...{

FileStream fs 
= new FileStream(@"C:Boot.ini", FileMode.Open,FileAccess.Read, FileShare.Read, 1024,FileOptions.Asynchronous);
Byte[] data 
= new Byte[100];

IAsyncResult ar 
= fs.BeginRead(data, 0, data.Length, null, null);
while (!ar.IsCompleted) ...{
Console.WriteLine(
"Operation not completed; still waiting.");
Thread.Sleep(
10);
}

Int32 bytesRead 
= fs.EndRead(ar);
fs.Close();
Console.WriteLine(
"Number of bytes read={0}", bytesRead);
Console.WriteLine(BitConverter.ToString(data, 
0, bytesRead));
}

我们可以看出轮询比较容易实现,但是效率可不高,因为我们要在花费一个线程来询问那个异步请求是否完成了,这样就浪费了一个线程。建议不要使用轮询。

下面我们看一下IAsyncResult的内容,前面已经用到了一个IsCompleted方法,后面可能还会用到它:

public interface IAsyncResult ...{
Object AsyncState 
...{ get; }
WaitHandle AsyncWaitHandle 
...{ get; }
Boolean IsCompleted 
...{ get; }
Boolean CompletedSynchronously 
...{ get; }
}

下面看一下轮询的另一种写法,效果和上面的一样:

public static void PollingWithIsCompleted() ...{
FileStream fs 
= new FileStream(@"C:Boot.ini", FileMode.Open,FileAccess.Read, FileShare.Read, 1024,FileOptions.Asynchronous);
Byte[] data 
= new Byte[100];
IAsyncResult ar 
= fs.BeginRead(data, 0, data.Length, null, null);
while (!ar.AsyncWaitHandle.WaitOne(10, false)) ...{
Console.WriteLine(
"Operation not completed; still waiting.");
}

Int32 bytesRead 
= fs.EndRead(ar);
fs.Close();
Console.WriteLine(
"Number of bytes read={0}", bytesRead);
Console.WriteLine(BitConverter.ToString(data, 
0, bytesRead));
}

3.方法回调,这个是这几种里面效率最高的

下面先看一个委托,因为所有的回调方法必须满足为这个委托的要求:

delegate void AsyncCallback(IAsyncResult ar);

using System;
using System.IO;
using System.Threading;
public static class Program ...{
private static Byte[] s_data = new Byte[100];
public static void Main() ...{

Console.WriteLine(
"Main thread ID={0}",
Thread.CurrentThread.ManagedThreadId);

FileStream fs 
= new FileStream(@"C:Boot.ini", FileMode.Open,FileAccess.Read, FileShare.Read, 1024,FileOptions.Asynchronous);
fs.BeginRead(s_data, 
0, s_data.Length, ReadIsDone, fs);
Console.ReadLine() ;
}


private static void ReadIsDone(IAsyncResult ar) ...{
Console.WriteLine(
"ReadIsDone thread ID={0}",
Thread.CurrentThread.ManagedThreadId);
FileStream fs 
= (FileStream) ar.AsyncState;
Int32 bytesRead 
= fs.EndRead(ar);
fs.Close();
Console.WriteLine(
"Number of bytes read={0}", bytesRead);
Console.WriteLine(BitConverter.ToString(s_data, 
0, bytesRead));
}

}


//输出
Main thread ID=1
ReadIsDone thread ID
=4
Number of bytes read
=100
5B
-62-6F-6F-74-20-6C-6F-61-64-65-72-5D-0D-0A-74-69-6D-65-6F-
75-74-3D-33-30-0D-0A-64-65-66-61-75-6C-74-3D-6D-75-6C-74-69-
28-30-29-64-69-73-6B-28-30-29-72-64-69-73-6B-28-30-29-70-61-
72-74-69-74-69-6F-6E-28-31-29-5C-57-49-4E-44-4F-57-53-0D-0A-
5B
-6F-70-65-72-61-74-69-6E-67-20-73-79-73-74-65-6D-73-5D-0D

下面看一下如何利用c#的匿名方法更简单的实现:

public static void Main() ...{
Console.WriteLine(
"Main thread ID={0}",
Thread.CurrentThread.ManagedThreadId);
FileStream fs 
= new FileStream(@"C:Boot.ini", FileMode.Open,FileAccess.Read, FileShare.Read, 1024,FileOptions.Asynchronous);
Byte[] data 
= new Byte[100];

fs.BeginRead(data, 
0, data.Length,

delegate(IAsyncResult ar)
...{
Console.WriteLine(
"ReadIsDone thread ID={0}",
Thread.CurrentThread.ManagedThreadId);
Int32 bytesRead 
= fs.EndRead(ar);
fs.Close();
Console.WriteLine(
"Number of bytes read={0}", bytesRead);
Console.WriteLine(BitConverter.ToString(data, 
0, bytesRead));
}
, null);

Console.ReadLine();
}

下面看一下如何解决我们上面文件大小不同读取时间不一样的问题:

private static void ReadMultipleFiles(params String[] pathnames) ...{
for (Int32 n = 0; n < pathnames.Length; n++) ...{
Stream stream 
= new FileStream(pathnames[n], FileMode.Open,FileAccess.Read, FileShare.Read, 1024,FileOptions.Asynchronous);
new AsyncStreamRead(stream, 100,
delegate(Byte[] data)
...{
Console.WriteLine(
"Number of bytes read={0}", data.Length);
Console.WriteLine(BitConverter.ToString(data));
}
);
}


Console.WriteLine(
"Hit <Enter> to end this program...");
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;
stream.BeginRead(m_data, 
0, numBytes, ReadIsDone, null);
}


private void ReadIsDone(IAsyncResult ar) ...{
Int32 numBytesRead 
= m_stream.EndRead(ar);
m_stream.Close();
Array.Resize(
ref m_data, numBytesRead);
m_callback(m_data);
}

}
posted @ 2008-01-10 19:30  yijiangchunxue  阅读(263)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3