欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

.Net Core异步编程

程序员文章站 2022-03-09 13:41:43
...

.Net Core异步编程

一. 用async关键字修饰的方法

  1. 异步方法的返回值一般是Task,T是真正的返回值类型,Task.惯例:异步方法名字最好以Async结尾,这样方便我们只要是async
  2. 即使方法没有返回值,也最好吧返回值声明为非泛型的Task.
  3. 调用泛型方法时,一般在方法前加上await关键字,这样拿到的返回值就是泛型指定的T类型;
  4. 异步方法的"传染性": 一个方法中如果await调用,则这个方法也必须修饰为async
static async Task Main(string[] args)
{
	string fileName = "d:/1.txt";
    File.Delete(fileName);
    File.WriteAllTextAsync(fileName,"hello async");
    string s = await File.ReadAllTextAsync(fileName);
    Console.WriteLine(s);
}
static async Task Main(string[] args)
{
    /*string fileName = @"F:\a\1.txt";
            File.WriteAllText(fileName, "hello");
            string s = File.ReadAllText(fileName);
            Console.WriteLine(s);*/
    string fileName = @"F:\a\1.txt";
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 10000; i++)
    {
        sb.AppendLine("hello");
    }
    //这里如果不加await,会显示异常 因为还没写入完成就开始读取,读取是独占的
    await File.WriteAllTextAsync(fileName, sb.ToString());

    string s = await File.ReadAllTextAsync(fileName);

    //Task<string> t = File.ReadAllTextAsync(fileName);
    //string s = await t;
    Console.WriteLine(s);
}

如果同样的功能,既有同步方法,又有异步方法,那么首先使用异步方法. .Net5中,很多框架的方法也都支持异步:Main,WinForm时间处理函数.

对于不支持异步方法该怎么办?

Wait()(无返回值); Result(有返回值) 风险:死锁,尽量不用

static async Task Main(string[] args)
{
    int l = await DownloadHtmlAsync("https://www.youzack.com", @"F:\a\1.txt");
    Console.WriteLine("ok" + l);
}

/*static async Task DownloadHtmlAsync(string url, string fileame)
        {
            using (HttpClient httpClient = new HttpClient())
            {
                string html = await httpClient.GetStringAsync(url);
                await File.WriteAllTextAsync(fileame, html);
            }
        }*/

static async Task<int> DownloadHtmlAsync(string url, string fileame)
{
    using (HttpClient httpClient = new HttpClient())
    {
        string html = await httpClient.GetStringAsync(url);
        await File.WriteAllTextAsync(fileame, html);
        return html.Length;
    }
}

二. await关键字修饰的方法

await调用的等待期间,.NET会把当前的线程返回给线程池,等异步方法调用执行完毕后,框架会从线程池在取出来一个线程执行后续的代码.

Thread.CurrentThread.ManageThreadId 获得当前线程Id

验证:在耗时异步(写入大字符串)操作前后分别打印线程Id

static async Task Main(string[] args)
{
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 1000; i++)
    {
        sb.Append("XXXXXXXXXXXXXXXXX");
    }

    await File.WriteAllTextAsync(@"F:\a\1.txt", sb.ToString());
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
}

优化:到要等待的时候,如果发现已经执行结束了,那就没必要再切换线程了,剩下的代码就继续在之前的线程上就行执行了

三.异步方法不等于多线程

static async Task Main(string[] args)
{
    Console.WriteLine("之前" + Thread.CurrentThread.ManagedThreadId);
    double r = await CalcAsync(5000);
    Console.WriteLine($"r = {r}");
    Console.WriteLine("之后" + Thread.CurrentThread.ManagedThreadId);
}

public static async Task<double> CalcAsync(int n)
{
    Console.WriteLine("CalcAsync," + Thread.CurrentThread.ManagedThreadId);
    double result = 0;
    Random rand = new Random();
    for (int i = 0; i < n*n; i++)
    {
        result += rand.NextDouble();
    }
    return result;
}

结论: 异步方法的代码并不会自动在新线程中执行,除非把代码放到新线程中执行.

把要执行的代码以委托的形式传递给Task().Run().这样就会从线程池中出去一个线程执行我们的委托

await Task.Run(()=>{
    //耗时操作代码,可以返回return返回值
})
相关标签: .NET CORE c# .net