异步编程(一)

目录

“异步方法”:用async关键字修饰的方法

异步方法编写

注意:

.NET6中Main方法的生成

async背后的线程切换

 接口中的异步方法:

异步与yield:


“异步方法”:用async关键字修饰的方法

  1. 异步方法的返回值一般是Task<T>,T是真正的返回值类型,Task<int>。惯例:异步方法名字以Async结尾
  2. 即使方法没有返回值,也最好把返回值声明为非泛型的Task
  3. 调用泛型方法时,一般在方法前加上await关,这样拿到的返回值就是泛型指定的T类型
  4. 异步方法的“传染性”:一个方法中如果有await调用,则这个方法也必须修饰为async 
返回值可为void或Task
static async Task Main(string[] args)
{
    string filename="E:\Temp\a.txt";
    await File.WriteAllTextAsync(filename,"hello");
    string s=await File.ReadAllTextAsync(filename);
}

如果同样的功能,既有同步方法,又有异步方法,尽量使用异步方法
对于不支持的异步方法,Wait()(无返回值),Result()(有返回值)。有死锁风险,尽量不用

异步方法编写

int length = await DownloadHtmlAsync("http://www.baidu.com", @"e:\a.txt");
Console.WriteLine(length);

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

//线程池中的异步委托使用,在lamda表达式前加async修饰就可以使用异步编程

ThreadPool.QueueUserWorkItem(async (obj) =>
{
    while (true)
    {
        await File.WriteAllTextAsync(@"e:\a.txt", "aaaaaaaa");
        Console.WriteLine("xxxxxx");
    }
});
Console.Read();
注意:

在VS2022中,创建控制台应用主要使用的框架是.NET6.0,而这个只有一个WriteLine语句的控制台,就是.NET6.0的新模板,使用了顶级语句这个功能。只有.Net5.0及其以下版本,才会生成以前带Main和名称空间的模板。

使用顶级语句可直接在文件的根目录中编写可执行代码,而无需在类或方法中包装代码。 这意味着无需使用 Program 类和 Main 方法即可创建程序。 在这种情况下,编译器将使用入口点方法为应用程序生成 Program 类。

.NET6中Main方法的生成

在创建控制台应用时,勾选“不使用顶级语句”

static async Task Main(string[] args)
{
    int length = await DownloadHtmlAsync("http://www.baidu.com", @"e:\a.txt");
    Console.WriteLine(length);
}

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

async背后的线程切换

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

如果写入内容少,会发现线程Id不变。

Thread.CurrentThread.ManagedThreadId:获得当前线程Id

static async Task Main(string[] args)
{
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    StringBulider sb=new StringBulider();
    for(int i=0;i<10000;i++)
    {
    	sb.Append("XXXXXXXXXXXXXXXX");
    }
    await File.WriteAllTextAsync(@"e:\a.txt",sb.ToString());
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
}

 接口中的异步方法:

async是提示编译器为异步方法中的await代码进行分段处理的,而一个异步方法是否修饰了async对于方法的调用者来讲没区别,因此对于接口中的方法或抽象方法不能修饰为async

异步与yield:

yield return不仅能够简化数据的返回,而且可以让数据处理“流水线化”,提升性能

static IEnumerable<string> Test()
{
    yield return "hello";
    yield return "hi";
    yield return "ooo";
}

在旧版C#中,async方法中不能用yield。从C#8.0开始,把返回值声明为IAsyncEnumerable(不要带Task),然后遍历的时候用await foreach()即可

static async Task Main(string[] args)
{
    await foreach(var s in Test())
    {
        Console.WriteLine(s);
    }

}

static async IAsyncEnumerable<string> Test()
{
    yield return "hello";
    yield return "hi";
    yield return "ooo";
}

ASP.NET Core和控制台项目中没有SynchronizationContext,因此不用管ConfigureAwait(false)等。不要同步、异步混用

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值