基础知识:如下所示:
1.NTFS文件系统设备驱动程序总是以同步方式执行一些操作,不管具体如何打开文件。
2.使用FileOptions.Asynchronous标志来表明异步执行IO操作,此时调用XxxAsync函数可以获得最佳性能。
3.不使用FileOptions.Asynchronous标志来表明同步执行IO操作,此时调用Xxx函数可以获得最佳性能。
执行同步IO操作:流程如下图所示:
执行异步IO操作:流程如下图所示:
async操作符:具有以下特性:
1.使用async操作符来标记的函数就是异步函数。
2.异步函数的返回类型只能是void或者Task或者Task<T>。
3.异步函数的参数不能使用out或者ref操作符。
4.当异步函数返回类型为Task<T>时,异步函数体就返回T类型变量;否则就什么都不返回。
5.不能将应用程序的Main函数转变成异步函数。
6.不能将类型的构造函数,属性访问器函数以及事件访问器函数转变成异步函数。
7.编译器执行async操作符的流程如下所示:
1>.生成一个派生自IAsyncStateMachine类的状态机类。
2>.创建状态机对象,并设置该对象的异步函数生成器字段,初始状态字段以及实参字段。
3>.调用状态机对象的Start函数来启动状态机。
4>.当异步函数返回类型为void时就什么都不返回。
5>.当异步函数返回类型为Task时就返回Task对象。该对象会在状态机对象执行完毕时自动完成。
6>.当异步函数返回类型为Task<T>时就返回Task<T>对象。该对象会在状态机对象执行完毕时自动完成,并将异步函数的返回结果填充到Result字段中。
await操作符:具有以下特性:
1.await操作符只能在异步函数内部使用。
2.不能在catch,finally以及unsafe块中使用await操作符。
3.不能在await操作符之前获得一个支持线程所有权或递归的锁,并在await操作符之后释放它。
4.在查询表达式中,await操作符只能在初始from子句的第一个集合表达式中使用;或者在join子句的集合表达式中使用。
5.编译器执行await操作符的流程如下所示:
1>.调用操作对象的GetAwaiter函数来获取等待者对象。
2>.操作以同步方式执行时,流程如下所示:
1>>.调用等待者对象的IsCompleted属性。该属性将返回true。
2>>.调用等待者对象的GetResult函数。该函数要么抛出异常来表示操作失败;要么返回结果来表示操作成功,然后调用线程从await操作符处继续向下执行。
3>.操作以异步方式执行时,流程如下所示:
1>>.调用等待者对象的IsCompleted属性。该属性将返回false。
2>>.调用等待者对象的OnCompleted函数。该函数接收一个委托。该委托执行流程如下所示:
1>>>.调用线程进入到await操作符位置处。
2>>>.调用等待者对象的GetResult函数。该函数要么抛出异常来表示操作失败;要么返回结果来表示操作成功,然后调用线程从await操作符处继续向下执行。
3>>.调用线程从await操作符处直接返回。
4>>.等待者对象完成时,就调用委托。
6.可以使用TaskFactory.FromAsync函数将基于BeginXXX函数和EndXXX函数的异步编程模型转换成基于Task的异步编程模型。但是尽量不要使用IAsyncResult类型作为参数的TaskFactory.FromAsync函数,因为它们性能低效。参考代码如下所示:
private static async void StartServer()
{
while (true)
{
var pipe = new NamedPipeServerStream(c_pipeName, PipeDirection.InOut, -1, PipeTransmissionMode.Message, PipeOptions.Asynchronous | PipeOptions.WithThrough);
// 异步的接受客户端连接
// 注意:NamedPipeServerStream使用旧的异步编程模型
// 我用TaskFactory的FromAsync函数将旧的异步编程模型转换成Task异步编程模型
await Task.Factory.FromAsync(pipe.BeginWaitForConnection, pipe.EndWaitForConnection, null);
// 开始为客户端服务,因为是异步的,所以可以立即返回
ServiceClientRequestAsync(pipe);
}
}
7.可以使用TaskCompletionSource类型将基于事件的异步编程模型转换成基于Task的异步编程模型。参考代码如下所示:
private static async Task<String> AwaitWebClient(Uri uri)
{
// System.Net.WebClient类支持基于事件的异步编程模型
var wc = new System.Net.WebClient();
// 创建TaskCompletionSource及其基础Task对象
var tcs = new TaskCompletionSource<String>();
// 字符串下载完毕后,WebClient对象引发DownloadStringCompleted事件
// 从而完成TaskCompletionSource对象
wc.DownloadStringCompleted += (s, e) => {
if (e.Cancelled) tcs.SetCanceled();
else if (e.Error != null) tcs.SetException(e.Error);
else tcs.SetResult(e.Result);
};
// 启动异步操作
wc.DownloadStringAsync(uri);
// 现在可以等待TaskCompletionSource的Task对象
String result = await tcs.Task;
return result;
}
8.向Task.ConfigureAwait函数传递true相当于根本没有调用该函数;否则await操作符就不查询调用线程的SynchronizationContext对象,当线程池线程结束Task对象时会直接完成它,await操作符后面的代码通过线程池线程执行。
IO请求优先级:Windows允许线程在发出IO请求时指定优先级,但是FCL还没有包含这个功能。此时可以使用P/Invoke本机Win32函数来实现这个功能,参考代码如下所示:
internal static class ThreadIO
{
public static BackgroundProcessingDisposer BeginBackgroundProcessing(Boolean process = false)
{
ChangeBackgroundProcessing(process, true);
return new BackgroundProcessingDisposer(process);
}
public static void EndBackgroundProcessing(Boolean process = false)
{
ChangeBackgroundProcessing(process, false);
}
private static void ChangeBackgroundProcessing(Boolean process, Boolean start)
{
Boolean ok = false;
if (process)
{
ok = SetPriorityClass(GetCurrentWin32ProcessHandle(), start ? ProcessBackgroundMode.Start : ProcessBackgroundMode.End);
}
else
{
ok = SetThreadPriority(GetCurrentWin32ThreadHandle(), start ? ThreadBackgroundMode.Start : ThreadBackgroundMode.End);
}
if (!ok)
{
throw new Win32Exception();
}
}
// 这个结构使C#的using语句能终止后台处理模式
public struct BackgroundProcessingDisposer
{
private readonly Boolean m_process;
public BackgroundProcessingDisposer(Boolean process)
{
m_process = process;
}
public void Dispose()
{
EndBackgroundProcessing(m_process);
}
}
// 参见WIN32的THREAD_MODE_BACKGROUND_BEGIN和THREAD_MODE_BACKGROUND_END
private enum ThreadBackgroundMode
{
Start = 0x10000,
End = 0x20000
}
// 参见WIN32的PROCESS_MODE_BACKGROUND_BEGIN和PROCESS_MODE_BACKGROUND_END
private enum ProcessBackgroundMode
{
Start = 0x100000,
End = 0x200000
}
[DllImport("Kernel32", EntryPoint = "GetCurrentProcess", ExactSpelling = true)]
private static extern SafeWaitHandle GetCurrentWin32ProcessHandle();
[DllImport("Kernel32", ExactSpelling = true, SetLastError = true)]
[return:MarshalAs(UnmanagedType.Bool)]
private static extern Boolean SetPriorityClass(SafeWaitHandle hProcess, ProcessBackgroundMode mode);
[DllImport("Kernel32", EntryPoint = "GetCurrentThread", ExactSpelling = true)]
private static extern SafeWaitHandle GetCurrentWin32ThreadHandle();
[DllImport("Kernel32", ExactSpelling = true, SetLastError = true)]
[return:MarshalAs(UnmanagedType.Bool)]
private static extern Boolean SetThreadPriority(SafeWaitHandle hThread, ThreadBackgroundMode mode);
[DllImport("Kernel32", SetLastError = true, EntryPoint = "CancelSynchronousIo")]
[return:MarshalAs(UnmanagedType.Bool)]
private static extern Boolean CancelSynchronousIO(SafeWaitHandle hThread);
}