Async In C#5.0(async/await)学习笔记

这篇具有很好参考价值的文章主要介绍了Async In C#5.0(async/await)学习笔记。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

此文为Async in C#5.0学习笔记

1、在async/await之前的异步

方式一:基于事件的异步Event-based Asynchronous Pattern (EAP).

private void DumpWebPage(Uri uri)
{
    WebClient webClient = new WebClient();
    webClient.DownloadStringCompleted += OnDownloadStringCompleted;
    webClient.DownloadStringAsync(uri);
}
private void OnDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs eventArgs)
{
    m_TextBlock.Text = eventArgs.Result;
}

方式二:基于IAsyncResult接口的异步

private void LookupHostName()
{
    object unrelatedObject = "hello";
    Dns.BeginGetHostAddresses("oreilly.com", OnHostNameResolved, unrelatedObject);
}
private void OnHostNameResolved(IAsyncResult ar)
{
    object unrelatedObject = ar.AsyncState;//上文中的hello字符串
    IPAddress[] addresses = Dns.EndGetHostAddresses(ar);
    // Do something with addresses
}

方式三:回调

void GetHostAddress(string hostName, Action<IPAddress> callback)
{
    //..
}

private void LookupHostName2()
{
    GetHostAddress("oreilly.com", OnHostNameResolved);
}
private void OnHostNameResolved(IPAddress address)
{
    // Do something with address
}

private void LookupHostName3()
{
    GetHostAddress("oreilly.com", address =>
    {
        // Do something with address and aUsefulVariable
    });
}

方式四:使用Task,尤其是Task<T>

private void LookupHostNameByTask()
{
    Task<IPAddress[]> ipAddressesPromise = Dns.GetHostAddressesAsync("oreilly.com");
    ipAddressesPromise.ContinueWith(_ =>
    {
        IPAddress[] ipAddresses = ipAddressesPromise.Result;
        // Do something with address
        Console.WriteLine("In ContinueWith");//后输出
    });
    Console.WriteLine("After ContinueWith");//先输出
}

共同的缺陷:必须将方法分为两部分
乱如麻的递归

private void LookupHostNames(string[] hostNames)
{
    LookUpHostNamesHelper(hostNames, 0);
}
private static void LookUpHostNamesHelper(string[] hostNames, int i)
{
    Task<IPAddress[]> ipAddressesPromise = Dns.GetHostAddressesAsync(hostNames[i]);
    ipAddressesPromise.ContinueWith(_ =>
    {
        IPAddress[] ipAddresses = ipAddressesPromise.Result;
        // Do something with address
        if (i + 1 < hostNames.Length)
        {
            LookUpHostNamesHelper(hostNames, i + 1);
        }
    });
}

2、使用Async

private async void DumpWebPageAsync(string uri)
{
    WebClient webClient = new WebClient();
    string page = await webClient.DownloadStringTaskAsync(uri);
    Console.WriteLine(page);
}

async/await

Task<string> myTask = webClient.DownloadStringTaskAsync(uri);
// Do something here
string page = await myTask;

注意,下面这样操作可能会有隐患,当firstTask有异常时,将不执行await secondTask

Task<string> firstTask = webClient1.DownloadStringTaskAsync("http://oreilly.com");
Task<string> secondTask = webClient2.DownloadStringTaskAsync("http://simple-talk.com");
string firstPage = await firstTask;
string secondPage = await secondTask;

3、Async方法的返回类型

1、void
2、Task
3、Task<T>

4、Async方法具有传递性

private async Task<int> GetPageSizeAsync(string url)
{
    WebClient webClient = new WebClient();
    string page = await webClient.DownloadStringTaskAsync(url);
    return page.Length;
}

private async Task<string> FindLargestWebPage(string[] urls)
{
    string largest = null;
    int largestSize = 0;
    foreach (string url in urls)
    {
        int size = await GetPageSizeAsync(url);
        if (size > largestSize)
        {
            size = largestSize;
            largest = url;
        }
    }
    return largest;
}

5、Async匿名委托和Lambdas表达式

Func<Task<int>> getNumberAsync = async delegate { return 3; };
Func<Task<string>> getWordAsync = async () => "hello";

6、await实际上做了啥?

同时执行下面两个分支
1、从当前行返回跳出函数,执行其他代码
2、等待await异步执行完成后,继续执行当行后面的语句
注意不恰当的大量使用异步,会必正常使用同步慢。

6、哪里不能使用await

1、catch和finally块

/// <summary>
/// 错误的写法
/// </summary>
private async void InvalidMethodAsync()
{
    var webClient = new WebClient();
    string page;
    try
    {
        page = await webClient.DownloadStringTaskAsync("http://oreilly.com");
    }
    catch (WebException)
    {
        page = await webClient.DownloadStringTaskAsync("http://oreillymirror.com");
    }
}
/// <summary>
/// 正确的写法
/// </summary>
private async void InsteadMethodAsync()
{
    bool failed = false;
    var webClient = new WebClient();
    string page;
    try
    {
        page = await webClient.DownloadStringTaskAsync("http://oreilly.com");
    }
    catch (WebException)
    {
        failed = true;
    }
    if (failed)
    {
        page = await webClient.DownloadStringTaskAsync("http://oreillymirror.com");
    }
}

2、lock块

不在lock内使用await

private async void LockAsync()
{
    var sync = new object();
    lock (sync)
    {
        // Prepare for async operation
    }
    int myNum = await Task.Run(() => { Thread.Sleep(5000); return 1; });
    lock (sync)
    {
        // Use result of async operation
    }
}

3、LINQ查询表达式

private async void LINQQueryAsync()
{
    var alexsInts = new List<int>();
    IEnumerable<Task<int>> tasks = alexsInts
                                   .Where(x => x != 9)
                                   .Select(async x => await DoSomthingAsync(x) + await DoSomthingElseAsync(x));
    IEnumerable<int> transformed = await Task.WhenAll(tasks);
}

private async Task<int> DoSomthingAsync(int x)
{
    return await Task.Run(() => { return x * 2; });
}

private async Task<int> DoSomthingElseAsync(int x)
{
    return await Task.Run(() => { return x + 2; });
}

4、Unsafe Code

Async In C#5.0(async/await)学习笔记,c#,笔记

7、异常捕获

异步内的异常不会直接抛出,可通过Task的IsFaulted判断

private async void ExceptionCaptureAsync()
{
    var task = ThrownExceptionAsync();
    Console.WriteLine($"1 task.IsFaulted={task.IsFaulted}");
    try
    {
        var result=await task;
        Console.WriteLine("Finished");
    }
    catch(Exception ex)
    {
        Console.WriteLine($"2 Exception:{ex.Message}");
    }
    Console.WriteLine("3 Exit ExceptionCaptureAsync");
}

private async Task<int> ThrownExceptionAsync()
{
    throw new Exception("In ThrownExceptionAsync");
}

输出结果:
Async In C#5.0(async/await)学习笔记,c#,笔记

8、async方法在需要之前是同步的

一般来说,async方法,在遇到第一个await之前是同步的。
其他情况:

  • 获取task的result
  • 未到达await时已经return
  • 运行了异步代码(但已执行完成)
  • 到达await时,异步方法也已执行完成

9、基于任务的异步模式(Task-Based Asynchronous Pattern,TAP)

同步方法

  • 有或没有参数,尽量避免ref与out参数
  • 有返回类型
  • 正确的方法名
  • 常见或预期的异常是返回类型的一部分,意外异步应该把抛出
    如:
public static IPHostEntry GetHostEntry(string hostNameOrAddress)

异步方法

  • 有或没有参数,不能有ref或out参数
  • 返回类型为Task或Task<T>
  • 命名格式为NameAsync(以Async结尾)
  • 错误的使用应直接抛出,其他异常在Task内处理
public static async Task<IPHostEntry> GetHostEntryAsync(string hostNameOrAddress)

10、使用Task进行计算密集型操作

Task t = Task.Run(() => MyLongComputation(a, b));

await Task.Run(() => MyLongComputation(a, b));
private async Task<int> TaskDemoAsync()
{
    int a = 0, b = 0;
    CancellationToken cancellationToken = new CancellationToken();
    CustomTaskScheduler taskScheduler = new CustomTaskScheduler();

    var t1 = Task.Factory.StartNew(() => { return MyLongComputation(a, b); },
                                    cancellationToken,
                                    TaskCreationOptions.LongRunning,
                                    taskScheduler);
    return await t1;
}

private static int MyLongComputation(int a,int b)
{
    return a + b;
}
//https://www.infoworld.com/article/3063560/how-to-build-your-own-task-scheduler-in-csharp.html
public sealed class CustomTaskScheduler : TaskScheduler, IDisposable
{
    private BlockingCollection<Task> tasksCollection = new BlockingCollection<Task>();
    private readonly Thread mainThread = null;
    public CustomTaskScheduler()
    {
        mainThread = new Thread(new ThreadStart(Execute));
        if (!mainThread.IsAlive)
        {
            mainThread.Start();
        }
    }
    private void Execute()
    {
        foreach (var task in tasksCollection.GetConsumingEnumerable())
        {
            TryExecuteTask(task);
        }
    }
    protected override IEnumerable<Task> GetScheduledTasks()
    {
        return tasksCollection.ToArray();
    }
    protected override void QueueTask(Task task)
    {
        if (task != null)
            tasksCollection.Add(task);
    }
    protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
    {
        return false;
    }
    private void Dispose(bool disposing)
    {
        if (!disposing) return;
        tasksCollection.CompleteAdding();
        tasksCollection.Dispose();
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

11、创建Puppet Task

//没有PermissionDialog类
//没有async关键词
private Task<bool> GetUserPermission()
{
    // Make a TaskCompletionSource so we can return a puppet Task
    TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
    // Create the dialog ready
    PermissionDialog dialog = new PermissionDialog();
    // When the user is finished with the dialog, complete the Task using SetResult
    dialog.Closed += delegate { tcs.SetResult(dialog.PermissionGranted); };
    // Show the dialog
    dialog.Show();
    // Return the puppet Task, which isn't completed yet
    return tcs.Task;
}

private async void GetUserPermissionAsync()
{
    if(await GetUserPermission())
    {
        //Do something
    }
}

12、旧的异步交互

IAsyncResult BeginGetHostEntry(string hostNameOrAddress,
				AsyncCallback requestCallback,
				object stateObject)
IPHostEntry EndGetHostEntry(IAsyncResult asyncResult)

public static Task<IPHostEntry> GetHostEntryAsync(string hostNameOrAddress)
{
    TaskCompletionSource<IPHostEntry> tcs = new TaskCompletionSource<IPHostEntry>();
    Dns.BeginGetHostEntry(hostNameOrAddress, asyncResult =>
    {
        try
        {
            IPHostEntry result = Dns.EndGetHostEntry(asyncResult);
            tcs.SetResult(result);
        }
        catch (Exception e)
        {
            tcs.SetException(e);
        }
    }, null);
    return tcs.Task;
}

private async void FromAsyncDemo()
{
    string hostNameOrAddress = "www.baidu.com";
    var t = Task<IPHostEntry>.Factory.FromAsync<string>(Dns.BeginGetHostEntry,
            Dns.EndGetHostEntry,
            hostNameOrAddress,
            null);
    await t;
    Console.WriteLine($"Dns:{t.Result.AddressList.FirstOrDefault()}");
}

13、延时(Task.Delay)

一般延时

await Task.Run(() => Thread.Sleep(100));

使用Timer和TaskCompletionSource(直接使用Task.Delay即可)

private static Task Delay(int millis)
{
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
    System.Threading.Timer timer = new System.Threading.Timer(_ => tcs.SetResult(null), null, millis, Timeout.Infinite);
    tcs.Task.ContinueWith(delegate { timer.Dispose(); });
    return tcs.Task;
}

14、等待所有Task完成(Task.WhenAll)

private async void TaskWhenAllDemoAsync()
{
    List<Task<string>> tasks = new List<Task<string>>();
    List<string> domains = new List<string>() { "1", "2", "3" };
    var rnd = new Random((int)DateTime.Now.Ticks);
    foreach (string domain in domains)
    {
        tasks.Add(GetStringAsync(domain, rnd.Next(100, 1000)));
    }
    //等价
    //var tasks2 = domains.Select(domain => GetStringAsync(domain, rnd.Next(100, 1000)));

    var allTask = Task.WhenAll(tasks);
    var taskResult = await allTask;
    
    foreach (var str in taskResult)
    {
        Console.WriteLine($"domain:{str}");
    }
}

private async Task<string> GetStringAsync(string domain, int sleepTime)
{
    var task = Task.Run(() =>
    {
        Task.Delay(sleepTime);
        Console.WriteLine($"Delay:{sleepTime}ms in Domain:{domain}");
        return domain;
    });
    return await task;
}

输出结果:
Async In C#5.0(async/await)学习笔记,c#,笔记

15、等待Task列表中的任一个完成(Task.WhenAny)

public static Task WhenAny(IEnumerable tasks)

private async void WhenAnyDemoAsync()
{
    var domains = new List<string>() { "1", "2", "3" };
    var rnd = new Random((int)DateTime.Now.Ticks);            
    var tasks = domains.Select(domain => GetStringAsync(domain, rnd.Next(100, 1000))).ToList();
    //注意上面与下面运行的结果差别
    // The IEnumerable from Select is lazy, so evaluate it to start the tasks
    //var tasks = domains.Select(domain => GetStringAsync(domain, rnd.Next(100, 1000)));
    Task<Task<string>> anyTask=Task.WhenAny(tasks);//注意,如果没有ToList(),当前才执行tasks内的GetStringAsync函数
    Task<string> winner=await anyTask;
    string strDomain=await winner;
    Console.WriteLine($"Domain:{strDomain}");
    await Task.WhenAll(tasks);//注意,如果没有ToList,这里的task与上面的是两次结果
    Console.WriteLine($"============================\r\n");
}

16、自定义组合

超时时退出

private async Task<T> WithTimeout<T>(Task<T> task, int time)
{
    Task delayTask = Task.Delay(time);
    Task firstToFinish = await Task.WhenAny(task, delayTask);
    if (firstToFinish == delayTask)
    {
        // The delay finished first - deal with any exception
        _ = task.ContinueWith(HandleException);
        throw new TimeoutException();
    }
    return await task; // If we reach here, the original task already finished
}

private static void HandleException<T>(Task<T> task)
{
    if (task.Exception != null)
    {
        //Log Exception
        //Logging.LogException(task.Exception);
    }
}

17、取消异步操作

CancellationTokenSource cts = new CancellationTokenSource();
cancelButton.Click += delegate { cts.Cancel(); };
int result = await dbCommand.ExecuteNonQueryAsync(cts.Token);

foreach (var x in thingsToProcess)
{
cancellationToken.ThrowIfCancellationRequested();//then IsCanceled will be true
// Process x ...
}

18、异步操作期间返回进度

使用 IPRogress<T>

Task<byte[]> DownloadDataTaskAsync(Uri address,
CancellationToken cancellationToken,
IProgress<DownloadProgressChangedEventArgs> progress)

new Progress<int>(percentage => progressBar.Value = percentage);

private Task<byte[]> DownloadDataTaskAsync(Uri address,
                CancellationToken cancellationToken,
                IProgress<int> progress)
{
    var currPercent = 1;
    progress.Report(currPercent);
    return null;
}

private void ReturnProgress()
{
    var progress= new Progress<int>(percentage => progressBar1.Value = percentage);
    progress.ProgressChanged += Progress_ProgressChanged;
}

19、异步操作的生命周期

private async void btn_GetIcon_Click(object sender, EventArgs e)
{
    Console.Clear();
    Enqueue($"1\tStart in btn_GetIcon_Click");
    var task = GetFavIcon("www.csdn.net");
    Enqueue($"3\tStart await GetFavIcon");
    var ico = await task;
    Enqueue($"6\tFinish await in btn_GetIcon_Click,{ico}");
    while(queue.TryDequeue(out string result))
    {
        Console.WriteLine(result);
    }
    
}

private async Task<string> GetFavIcon(string url)
{
    Enqueue($"2\tIn GetFavIcon function");
    var task = Task.Run(() =>
    {
        Enqueue($"3\tStart to GetfavIcon for {url}");
        var spendTime = rndNum.Next(1000, 1500);
        Task.Delay(spendTime);
        Enqueue($"4\tSpend {spendTime}ms To Getfavicon for {url}");
        return url;
    });
    Enqueue($"3\tStart await in GetFavicon");
    var result = await task;
    Enqueue($"5\tFinish await in GetFavicon");
    return $"favicon:{result}";
}

private void Enqueue(string msg)
{
    queue.Enqueue($"{DateTime.Now:HH:mm:ss.FFFFFFF}\t{msg}");
}

输出结果:
Async In C#5.0(async/await)学习笔记,c#,笔记
序号为3的输出顺序可能不一致。

20、选择不使用SynchronizationContext(ConfigureAwait)

没太明白

21、异步方法的Result属性

var result = AlexsMethodAsync().Result;

程序会阻塞等待AlexsMethodAsync执行结束

22、异步的异常

async Task CatcherAsync()
{
    try
    {
        Console.Clear();
        Console.WriteLine("In CatcherAsync");
        var task = Thrower();
        Console.WriteLine("Before await Thrower");
        await task;
        Console.WriteLine("After await Thrower");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Cathc Exception in Catcher:{ex.Message}");
    }
}
async Task Thrower()
{
    await Task.Delay(100);
    throw new Exception("Exception in Thrower");
}

private async void btn_ExceptionDemo_Click(object sender, EventArgs e)
{
    await CatcherAsync();
}

输出结果:
Async In C#5.0(async/await)学习笔记,c#,笔记

23、使用.ContinueWith(HandleException)处理void类型异步

public static void ForgetSafely(this Task task)
{
    task.ContinueWith(HandleException);
}

private static void HandleException(Task task)
{
    //do something task.Exception
}

24、AggregateException和WhenAll

Task<Image[]> allTask = Task.WhenAll(tasks);
try
{
    await allTask;
}
catch
{
    foreach (Exception ex in allTask.Exception.InnerExceptions)
    {
        // Do something with exception
    }
}

25、尽量在同步模块时抛出异常

private Task<Image> GetFaviconAsync(string domain)
{
    if (domain == null) throw new ArgumentNullException("domain");
    return GetFaviconAsyncInternal(domain);
}
private async Task<Image> GetFaviconAsyncInternal(string domain)
{
    //...
}

26、异步里,finally不一定执行

await DelayForever()及finally里的代码没有执行文章来源地址https://www.toymoban.com/news/detail-815516.html

async void AlexsMethod()
{
    try
    {
        Console.WriteLine("Before DelayForever");
        await DelayForever();
        Console.WriteLine("After DelayForever");
    }
    finally
    {
        // Never happens
        Console.WriteLine("finally,After DelayForever");
    }
}
Task DelayForever()
{
    Console.WriteLine("IN DelayForever");
    return new TaskCompletionSource<object>().Task;
}

27、lock块内不能使用await

lock (sync)
{
// Prepare for async operation
}
int myNum = await AlexsMethodAsync();
lock (sync)
{
// Use result of async operation
}

if (DataInvalid())
{
	Data d = await GetNewData();
	// Anything could have happened in the await
	if (DataInvalid())
	{
		SetNewData(d);
	}
}

到了这里,关于Async In C#5.0(async/await)学习笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Promise、Async/Await 详解

            Promise是抽象异步处理对象以及对其进行各种操作的组件。Promise本身是同步的立即执行函数解决异步回调的问题, 当调用 resolve 或 reject 回调函数进行处理的时候, 是异步操作, 会先执行.then/catch等,当主栈完成后,才会去调用执行resolve/reject中存放的方法。      

    2024年02月14日
    浏览(39)
  • async/await 的理解和用法

    async放在函数前的一个修饰符,函数会默认返回一个Promise对象的resolve的值 1、await也是一个修饰符, 只能放在async定义的函数内 ,可以理解为 等待 2、await 修饰的是Promise对象: 获取Promise中返回的内容 (resolve或reject的参数), 且取到值后语句才会往下执行; 3、如果不是P

    2024年02月01日
    浏览(41)
  • 【C#】async和await 续

    在文章《async和await》中,我们观察到了一下客观的规律,但是没有讲到本质,而且还遗留了一个问题: 这篇文章中,我们继续看看这个问题如何解决! 我们再看看之前写的代码: 当时问题是,为啥 Task.Factory.StartNew 可以看到异步效果,而Task.Run中却是同步效果。 那其实是因为

    2024年02月15日
    浏览(42)
  • async_await 源码分析

    这篇文章主要是分析 async/await 这个语法糖,分析一下 async 和 await 是如何做到异步的。首先,我先抛出两个问题,各位可以先想一下。 await 之后的方法是何时执行,如何执行的? 为什么 await 之后的代码会在不同的线程执行? 要想知道 async/await 是怎么运行的,需要先写一个

    2024年02月12日
    浏览(41)
  • kotlin协程async与await

    kotlin协程async与await 输出: 3 3072 https://zhangphil.blog.csdn.net/article/details/129265638 https://zhangphil.blog.csdn.net/article/details/129265638 kotlin协程、线程切换,函数方法委托_zhangphil的博客-CSDN博客 runBlocking 内部启动的3个协程做耗时操作,从输出可以看到3个协程交叉并发执行,runBlocking 会等

    2024年02月05日
    浏览(38)
  • async和await的的基本使用

    说明: await’ expressions are only allowed within async functions and at the top levels of modules.ts(1308)

    2024年02月13日
    浏览(45)
  • promise及异步编程async await

    ECMAScript 6 新增了正式的 Promise(期约)引用类型,支持优雅地定义和组织异步逻辑。接下来几个版本增加了使用 async 和 await 定义异步函数的机制 JavaScript 是单线程事件循环模型。异步行为是为了优化因计算量大而时间长的操作,只要你不想为等待某个异步操作而阻塞

    2024年02月04日
    浏览(43)
  • async/await实现Promise.all()

    🐱个人主页: 不叫猫先生 🙋‍♂️作者简介:专注于前端领域各种技术,热衷分享,期待你的关注。 💫系列专栏:vue3从入门到精通 📝个人签名:不破不立 Promise.all() 方法接收一个 promise 的 iterable 类型(注:Array,Map,Set 都属于 ES6 的 iterable 类型)的输入,并且 只返回

    2024年01月18日
    浏览(45)
  • async/await 与console(C#)

    上一篇async/await 致WPF卡死问题(https://www.cnblogs.com/stephen2023/p/17725159.html),介绍主线程阻塞,async/await导致卡死问题,同样的代码在console下却并不会出现卡死。 并且await后的任务也是由“新线程”执行的,并非主线程执行。 对于如下含await的代码 可以类比于: WPF与Console不同

    2024年02月08日
    浏览(58)
  • 彻底理解Promise和async/await

    1.异步行为是 为了优化因计算量大而时间长的操作 . 2.pedding 待定: 表示尚未开始或正在进行中    fulfilled 解决: 表示已经成功完成    rejected 拒绝: 表示没有完成 3.从pedding状态切换到fulfilled状态或rejected状态后,状态就不会再改变.而且也不能保证promise比如会脱离待定状态. 因此

    2024年02月03日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包