计算限制的异步操作
如果CPU的使用率不到100%,表明当前运行的进程没有使用计算机全部计算能力(IO操作时,设备驱动管理器让硬件设备在干活儿,而CPU无事可做),此时可以并行执行计算,提高资源利用率,能显著提高应用程序的吞吐能力。
ThreadPool
Task
Parallel的静态方法For ,ForEach ,Invoke方法
PLINQ (Parallel LINQ)
定时计算限制操作Timer
1.System.Threading.Timer
2.System.Windows.Forms.Timer
3.System.Windows.Threading.DispatcherTimer
4.Windows.UI.Xaml.DispatcherTimer
5.System.Timers.Timer
本质是System.Threading.Timer的包装类,不建议使用
注意Timer.Change()方法的使用,防止调用时间重叠。
static void DoOneByOne()
{
Timer timer = null;
Random r = new Random();
timer = new Timer(x =>
{
Console.Write(Thread.CurrentThread.ManagedThreadId + " ");
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff"));
int second = r.Next(1, 11);
Thread.Sleep(second * 1000);
Console.WriteLine(second);
timer.Change(0, Timeout.Infinite);
}, null, 0, Timeout.Infinite);
Console.ReadKey();
}
IO限制的异步操作
IO限制的操作,允许将任务交给硬件设备处理,期间不占用线程和CPU资源。然而线程池线程需要处理IO操作的结果。
C#的异步函数 async await 返回值为Task类型
async关键字说明此方法为异步方法,编译器将方法的代码转换成实现了状态机的一个类型。(async方法不一定内部使用await,不使用await还会生成状态机代码,调用不再是异步了)
方法内部使用await关键字,await的方法内部分配一个Task对象并将他返回给async方法。实际上会在Task对象上调用ContinueWith,向它传递用于恢复状态机的方法,然后return此async方法(所以应该await一个返回值为task的方法)。
将来某个时候,设备驱动程序结束IO操作,一个线程池线程会通知Task对象,后者激活ContinueWith回调方法,造成一个线程恢复状态机。更具体地说,一个线程重新进入async方法,在await操作符位置开始执行。(C#CLR 648页)
async方法内部return string ;则它的返回值为Task<string> ;Task<string>是右边一起生成的状态机代码
ConfigureAwait(bool)
public async Task<int> DoSome() { string path; await Task.Run(() => { DoSomething(); //主线程执行到 await 启动任务,异步执行Task,此Task执行完毕, 会调用ContinueWith方法执行 【后续操作】 }).ConfigureAwait(false); //这里是异步Task执行完毕后(下面代码写了一个文件),恢复状态机需要执行的【后续操作】
//如果为true(默认值为true) 当线程执行完毕 ,恢复状态机执行后续代码时会尝试恢复上下文执行(web请求 ,如果原来线程已经返回线程池,HTTPContext将不能恢复,所以会不能恢复执行?); // (winform gui程序 会恢复为ui线程执行,ui线程不会停止所以总是会恢复执行,但是会阻塞(占用)ui线程,导致卡顿) //配置为false 则不会捕获上下文
path = AppDomain.CurrentDomain.BaseDirectory + "/a/a.txt";
System.IO.File.WriteAllText(path, DateTime.Now.ToString("HH:mm:ss.fff"));
return 1; }
异步编程模型
.NET Framework 提供了执行异步操作的三种模式:
1.异步编程模型 (Asynchronous Programming Model APM) 模式(也称 IAsyncResult 模式),在此模式中异步操作需要 Begin
和 End
方法(比如用于异步写入操作的 BeginWrite
和 EndWrite
)。
public class MyClass
{
public IAsyncResult BeginRead(
byte [] buffer, int offset, int count,
AsyncCallback callback, object state);
public int EndRead(IAsyncResult asyncResult);
}
2.基于事件的异步模式 (Event-based Asynchronous Parttern EAP),这种模式需要 Async
后缀,也需要一个或多个事件、事件处理程序委托类型和 EventArg
派生类型。 EAP 是在 .NET Framework 2.0 中引入的。
public class MyClass
{
public void ReadAsync(byte [] buffer, int offset, int count);
public event ReadCompletedEventHandler ReadCompleted;
}
3.基于任务的异步模式 (Task-based Asynchronous Parttern TAP) 使用一种方法来表示异步操作的启动和完成。 TAP 是在 .NET Framework 4 中引入的,并且它是在 .NET Framework 中进行异步编程的推荐使用方法。
public class MyClass { public Task<int> ReadAsync(byte [] buffer, int offset, int count); }
死锁的例子:
调用DealLock产生死锁
async Task WaitAsync()
{
//捕获当前上下文
await Task.Delay(TimeSpan.FromSeconds(2));//
//在这里视图使用捕获的上下文恢复继续执行,但是主线程在DealLock方法中Wait
}
//死锁
void DealLock()
{
Task task = WaitAsync();
task.Wait();//同步程序块,正在等待异步完成。
}
避免死锁:在WaitAsync方法await时使用ConfigureAwait(false)//
public async Task<JsonResult> UploadLink() { //await 导致等待异步方法执行完成 ,等待期间原线程返回线程池继续用于处理请求 (例如:winform中await 不会阻塞主线程,sleep会阻塞主线程) Result result = await GetLinkListAsync(table); //异步方法执行完成,尝试恢复线程 } public Task<Result> GetLinkListAsync(DataTable inkTable) { return Task.Run(() => { return GetLinkList(linkTable); }); }
来源:https://www.cnblogs.com/fmys/p/9180432.html