C#异步编程的基本用法

异步编程

1.多线程

1.1.Thread类

Thread类的基本使用

//和java差不多,传入一个函数给委托
var thread= new Thread(()=>
{
	Consoel.WriteLine("do sth...");
});
//开始异步执行线程
thread.Start();
//线程睡眠
thread.Sleep(1000);
//让主线程等待
thread.Join();
//中止线程
try
{
	thread.Interrupt();
}
catch (ThreadInterruptedException e)
{
    Console.WriteLine(e);
    throw;
}

2.异步编程

2.1.Task类

task默认使用线程池进行通信,由系统自动分配线程异步执行

//创建一个新的线程并执行
var task = new Task(() => 
{
	Console.WriteLine("do sth")
}
);
task.Start();

2.2.async和await

async会将当前方法定义为异步方法,在编译时加入状态机进行线程的切换。

awaite会将当前函数线程挂起,线程空闲时会执行其他任务。

awaite只能在async方法中使用

//代码参考下面

2.3.使用channel进行通信

internal class Program
{
    private static async Task Main(string[] args)
    {
		//创建一个channel
        var channle = Channel.CreateUnbounded<Student>();
		//等待发送发发送完成
        await SendInfo(channle.Writer);
        //将发送状态设置为完成
		channle.Writer.Complete();
        //接收方读取信息
		await ReadInfo(channle.Reader);
        return;
    }

	//消息发送的异步方法
    static async Task SendInfo(ChannelWriter<Student> writer)
    {
        for (int i = 0; i < 10; i++)
        {
            await Task.Delay(200);
            await writer.WriteAsync(new Student { UserId = i, UserName = $"张三{i}" });
            System.Console.WriteLine($"{Environment.CurrentManagedThreadId}--发送消息--{Environment.CurrentManagedThreadId}--{i}");
        }
    }

	//消息接收的异步方法
    static async Task ReadInfo(ChannelReader<Student> reader)
    {
        await foreach (var item in reader.ReadAllAsync())
        {
            System.Console.WriteLine($"{Environment.CurrentManagedThreadId}--读取到内容{item.UserId}--{item.UserName}");
        }
    }
}

public class Student
{
    public long UserId;
    public string? UserName;
}

2.4.在同步方法中调用异步方法

  1. GetAwaiter().getResult();
  2. 使用弃元 _=FooAsync();
  3. 使用void返回值的异步方法

具体代码如下:

internal class Program
{
    public static void Main(string[] args)
    {
        var sw = Stopwatch.StartNew();
        Console.WriteLine("程序开始");

		//阻塞当前线程直到获取到值,常用
        FooAsync().GetAwaiter().GetResult();

		//使用fire and forget调用(弃元),无法获取到异常信息
        _ = FooAsync();

		//使用void返回值的异步方法,抛出异常可能会中止程序
        VoidFooAsync();

        for (int i = 0; i < 5; i++)
        {
            Thread.Sleep(200);
            Console.WriteLine($"{Environment.CurrentManagedThreadId}-当前值为: {i}");
        }
        Console.WriteLine($"程序耗时:{sw.ElapsedMilliseconds}ms");
        Console.ReadKey();
    }

    static async Task FooAsync()
    {
        await Task.Delay(200);
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine($"{Environment.CurrentManagedThreadId}-当前值为: {i}");
        }
    }

	static async void VoidFooAsync()
    {
        await Task.Delay(200);
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine($"{Environment.CurrentManagedThreadId}-当前值为: {i}");
        }

        throw new Exception();
    }
}

2.5.使用Cancellation来取消异步任务

创建一个CancellationTokenSource并传入变量,调用其Cancel方法时会取消任务并触发TaskCanceledException异常

var cts = new CancellationTokenSource();
//取消任务
cts.Cancel();
await Task.Delay(2000,cts.Token);
Console.WriteLine("任务已取消");

可以设置一段时间后自动取消任务。
两秒钟后任务会被取消,注意捕获异常。

var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2));
await Task.Delay(3000,cts.Token);
Console.WriteLine("任务已取消");

异常处理

var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2));
cts.Cancel();
try
{
    await Task.Delay(2000, cts.Token);
}
catch (TaskCanceledException e)
{
    Console.WriteLine(e);
    throw;
}
finally
{
    cts.Dispose();
}
Console.WriteLine("任务已取消");

2.6.设置任务超时

//设置一个delay任务,如果这个任务先执行完则任务没有超时,否则任务超时
//执行任务a
var taskA = new Task(() => { Console.WriteLine("这是一个任务"); });
taskA.Start();
//等待任务执行
var taskB = await Task.WhenAny(taskA,Task.Delay(2000));
//如果先执行完的不是任务a,则任务超时了
if (taskB != taskA )
{
    Console.WriteLine("你的任务超时了,做点什么吧");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值