.NET 异步编程

心已入冬 提交于 2020-01-02 05:08:22

计算限制的异步操作

如果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);
        });
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!