C# 异步调用备忘

1.将一个同步方法封装为异步方法

a. 无返回值的封装

public async Task ReadAudioAsync(byte[] audio)
{
    await Task.Run(() => PlaySound(audio, IntPtr.Zero, (uint)(SoundFlags.SND_MEMORY | SoundFlags.SND_SYNC)));
}

b.有返回值的封装

public async Task<bool> ReadAudioAsync(byte[] audio)
    {
        var tcs = new TaskCompletionSource<bool>();

        await Task.Run(() =>
        {
            bool result = PlaySound(audio, IntPtr.Zero, (uint)(SoundFlags.SND_MEMORY | SoundFlags.SND_ASYNC));
            tcs.SetResult(result);
        });

        return await tcs.Task;
    }

如果调用一个返回值为 async Task 的方法,不想等待,也不想要返回结果,可以在方法前加 _ =,如下:

_ = ReadAudioAsync(new byte[]{});

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

a. 异步调用,不等待异步方法的完成。或者定义一个 async void 方法,调用时就像同步方法一样调用即可。

Task.Run(async () =>
{
    await ...
    await ...
});

b. 同步调用,等待异步方法的完成

void Main()
{
    //有返回值的等待
    var task = GetDataAsync();
    var data = task.Result;
    
    //无返回值的等待
    DosthAsync().Wait();
}

async Task<string> GetDataAsync()
{
    await Task.Delay(1000); // 模拟异步操作
    return "Hello, World!";
}

async Task DosthAsync()
{
    await Task.Delay(1000); // 模拟异步操作
}

3. 在异步方法返回一个常量

public async Task<bool> Download()
{
    var source = new TaskCompletionSource<bool>();
    source.SetResult(true);
    return await source.Task;
}
                

4. 在异步方法中等待一定时长,不要使用 Theading.Sleep,使用如下代码

await Task.Delay(0);

 5. 匿名异步等待

await new Func<Task>(async () =>
{
    await Task.Delay(1000); // 模拟异步操作
    Console.WriteLine("异步操作完成");
})();

 6. 从一个内部匿名函数返回自定义类型(使用公共变量)

public async Task<IQueryable<TResult>> Select<TResult>(System.Linq.Expressions.Expression<Func<BookPage, TResult>> selector)
{
    IQueryable<TResult> result = null;

    await SqlcipherConnectionLocal.RunInTransactionAsync(async (connection) =>
    {
        var data = connection.Table<BookPage>().AsQueryable().Select(selector);
        result = await Task.FromResult(data);
    });

    return result;
}

7. 延迟等待异步结果(原本需要5秒,但延迟等待共耗时3秒)

async void Main()
{
    //开始一个异步任务task,但并不立即等待结果
    Task<int> task = MyTask();

    //做自己的事情
    await Task.Delay(2000);

    //等待task结果返回
    int result = await task;
    
    Console.WriteLine($"{DateTime.Now}\tresult: {result}");

    Console.ReadLine();
}

public async Task<int> MyTask()
{
    Console.WriteLine($"{DateTime.Now}\ttask started.");

    await Task.Delay(3000);

    Console.WriteLine($"{DateTime.Now}\ttask completed.");

    return 1;
}

 8. 创建一个双线执行的存取任务

Random random = new Random();

async void Main()
{
    var tasks = CreateSequencialTasks(10);
    
    //朗读时需要按顺序获取创建的音频
    foreach (var task in tasks)
    {
        string audio = await task;
        await ReadAudio(audio);
    }

    Console.WriteLine("all over.");
    Console.ReadLine();
}

//创建一批顺序执行的任务
List<Task<string>> CreateSequencialTasks(int count)
{
    var result = new List<Task<string>>();

    Task<string> previousTask = Task.FromResult(string.Empty);

    for (int i = 0; i < count; i++)
    {
        int currentIndex = i; 
        previousTask = CreateNextTask(previousTask, currentIndex);
        result.Add(previousTask);
    }
    return result;
}

Task<string> CreateNextTask(Task<string> antecedent, int index)
{
    return antecedent.ContinueWith(async task =>
    {
        string previousResult = await task;
        string nextResult = await CreateAudio(index);
        return nextResult;
    }).Unwrap();
}


//朗读语音
public async Task ReadAudio(string audio)
{
    Console.WriteLine($"{DateTime.Now} \t ReadAudio({audio}) started.");

    await Task.Delay(random.Next(2000, 5001));

    Console.WriteLine($"{DateTime.Now} \t ReadAudio({audio}) completed.");
}

//生成语音
public async Task<string> CreateAudio(int index)
{
    Console.WriteLine($"{DateTime.Now} \t CreateAudio({index}) started.");

    await Task.Delay(random.Next(500, 3001));

    Console.WriteLine($"{DateTime.Now} \t CreateAudio({index}) completed.");

    return "Audio" + index;
}

 9. 永远可附加执行的队列

async Task Main()
{
    var task1 = CreateAudio(1);
    
    await Task.Delay(5001);  // 等待5秒钟

    //即便task1已经结束了,也可以附加 ContinueWith 执行
    var task2 = task1.ContinueWith(async previousTask =>
    {
        return await CreateAudio(2);
    }).Unwrap();
    
    var result1 = await task1;
    var result2 = await task2;

    Console.ReadLine();
}

public async Task<string> CreateAudio(int index)
{
    Console.WriteLine($"{DateTime.Now} \t CreateAudio({index}) started.");

    await Task.Delay(new Random().Next(500, 3001));

    Console.WriteLine($"{DateTime.Now} \t CreateAudio({index}) completed.");

    return "Audio" + index;
}

10. 多线程连续任务使用异步实现示例

Random random = new Random();

//音频生成任务链
Task<string> lastCreateTask = Task.FromResult(string.Empty);

//音频朗读任务链
Task lastReadTask = Task.CompletedTask;

void Main()
{
    for (var i = 0; i < 10; i++)
    {
        addTask(i);
    }
    
    Console.ReadLine();
}

void addTask(int input)
{
    //新增音频生成任务到任务链
    var createTask = lastCreateTask.ContinueWith(async previousTask =>
        {
            return await CreateAudio(input);
        }).Unwrap();

    lastCreateTask = createTask;

    //新增音频朗读任务到任务链
    var readTask = lastReadTask.ContinueWith(async previousTask =>
    {
        await ReadAudio(createTask);
    }).Unwrap();

    lastReadTask = readTask;
}

//朗读语音
async Task ReadAudio(Task<string> task)
{
    var audio = await task;
    Console.WriteLine($"{DateTime.Now} \t ReadAudio({audio}) started.");

    await Task.Delay(random.Next(2000, 5001));

    Console.WriteLine($"{DateTime.Now} \t ReadAudio({audio}) completed.");
}

//生成语音
async Task<string> CreateAudio(int index)
{
    Console.WriteLine($"{DateTime.Now} \t CreateAudio({index}) started.");

    await Task.Delay(new Random().Next(500, 3001));

    Console.WriteLine($"{DateTime.Now} \t CreateAudio({index}) completed.");

    return "Audio" + index;
}

posted on 2023-10-21 13:54  空明流光  阅读(9)  评论(0编辑  收藏  举报

导航