异步函数

此入门教程是记录下方参考资料视频的过程
开发工具:Visual Studio 2019

async和await关键字可以让你写出和同步代码一样简洁且结构相同的异步代码

await

    var result=await expression;
    statement(s);
var awaiter=expression.GetAwaiter();
awaiter.OnCompleted(()=>
{
    var result=awaiter.GetResult();
    statement(s);
});
static async Task Main(string[] args)
{

}

async修饰符

异步方法如何执行

static async Task Main(string[] args)
{

}

可以await什么?

捕获本地状态

static async Task Main(string[] args)
{

}
static async void DisplayPrimeCounts()
{
    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine(await GetPrimesCountAsync(i * 1000000 + 2, 1000000));
    }
}
static Task<int> GetPrimesCountAsync(int start, int count)
{
    return Task.Run(() =>
    ParallelEnumerable.Range(start, count).Count(n =>
            Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0)));
}

await之后在哪个线程上执行

UI上的await

public MainWindow()
{
    InitializeComponent();

}

async void Go()
{
    this.Button1.IsEnabled = false;

    for (int i = 1; i < 5; i++)
    {
        this.TextMessage.Text += await this.GetPrimesCountAsync(i * 1000000, 1000000) + " primes between " + (i * 1000000) + " and " + ((i + 1) * 1000000 - 1) + Environment.NewLine;
    }

    this.Button1.IsEnabled = true;
}

Task<int> GetPrimesCountAsync(int start, int count)
{
    return Task.Run(() =>
        ParallelEnumerable.Range(start, count).Count(n =>
            Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0)));
}

private void Button1_Click(object sender, RoutedEventArgs e)
{
    this.TextMessage.Text = null;
    this.Go();
}
async void Go()
{
    this.Button1.IsEnabled = false;

    string[] urls = "www.bing.com www.baidu.com www.cnblogs.com".Split();
    int totalLength = 0;
    try
    {
        foreach (string url in urls)
        {
            var uri = new Uri("http://" + url);
            byte[] data = await new WebClient().DownloadDataTaskAsync(uri);
            this.TextMessage.Text += "Length of " + url + " is " + data.Length + Environment.NewLine;
            totalLength += data.Length;
        }
        this.TextMessage.Text += "Total length " + totalLength;
    }
    catch (WebException e)
    {
        this.TextMessage.Text += "Error:" + e.Message;
    }
    finally
    {
        this.Button1.IsEnabled = true;
    }

}

private void Button1_Click(object sender, RoutedEventArgs e)
{
    this.TextMessage.Text = null;
    this.Go();
}

伪代码:

为本线程设置同步上下文(WPF)
while(!程序结束)
{
    等着消息队列中发生一些事情
    发生了事情,是哪种消息?
    键盘/鼠标消息->触发event handler
    用户BeginInvoke/Invoke 消息->执行委托
}

附加到UI元素的event handler通过消息循环执行
因为在UI线程上await,continuation将消息发送到同步上下文上,该同步上下文通过消息循环执行,来保证整个Go方法伪并发的在UI线程上执行

与粗粒度的并发相比

1、例如使用BackgroundWorker,不推荐这样写异步函数

void Go()
{
    for (int i = 1; i < 5; i++)
    {
        int result = this.GetPrimesCount(i * 1000000, 1000000);
        this.Dispatcher.BeginInvoke(new Action(() =>
        this.TextMessage.Text += result + " primes between " + (i * 1000000) + " and " + ((i + 1) * 1000000 - 1) + Environment.NewLine));
    }
    this.Dispatcher.BeginInvoke(new Action(() => this.Button1.IsEnabled = true));
}

int GetPrimesCount(int start, int count)
{
    return ParallelEnumerable.Range(start, count).Count(n =>
            Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0));
}

private async void Button1_Click(object sender, RoutedEventArgs e)
{
    this.TextMessage.Text = null;
    this.Button1.IsEnabled = false;

    Task.Run(() => this.Go());
}

编写异步函数

static async Task Main(string[] args)
{

static async Task Main(string[] args)
{
}
static async Task Go()
{
    await PrintAnswerToLife();
    Console.WriteLine("Done");
}
static async Task PrintAnswerToLife()
{
    await Task.Delay(5000);
    int answer = 21 * 2;
    Console.WriteLine(answer);
}
static Task PrintAnswerToLide()
{
    var tcs = new TaskCompletionSource<object>();
    var awaiter = Task.Delay(5000).GetAwaiter();
    awaiter.OnCompleted(() =>
    {
        try
        {
            awaiter.GetResult();
            int answer = 21 * 2;
            Console.WriteLine(answer);
            tcs.SetResult(null);
        }
        catch (Exception e)
        {
            tcs.SetException(e);
        }
    });
    return tcs.Task;
}

编写异步函数,富客户端场景下

返回Task

static async Task Main(string[] args)
{

}
static async Task<int> GetAnswerToLiife()
{
    await Task.Delay(5000);
    int answer = 21 * 2;
    return answer;
}
static async Task PrintAnswerToLife()
{
    int answer = await GetAnswerToLife();
    Console.WriteLine(answer);
}
static async Task<int> GetAnswerToLife()
{
    await Task.Delay(5000);
    int answer = 21 * 2;
    return answer;
}
static void Main(string[] args)
{

}
static void Go()
{
    PrintAnswerToLife();
    Console.WriteLine("Done");
}
static void PrintAnswerToLife()
{
    int answer = GetAnswerToLife();
    Console.WriteLine(answer);
}
static int GetAnswerToLife()
{
    Thread.Sleep(5000);
    int answer = 21 * 2;
    return answer;
}

C#中如何设计异步函数

编译器能对异步函数生成Task意味着什么?

异步调用图执行

static async Task Main(string[] args)
{

并行(Parallelism)

    var task1=PrintAnswerToLife();
    var task2=PrintAnswerToLife();
    await task1;
    await task2;

异步Lambda表达式

static async Task Main(string[] args)
{
    Func unnamed = async () =>
    {
        await Task.Delay(1000);
        Console.WriteLine("Foo");
    };

    await NamedMethod();
    await unnamed();
}
static async Task NamedMethod()
{
    await Task.Delay(1000);
    Console.WriteLine("Foo");
}
myButton.Click+=async (sender,args)=>
{
    await Task.Delay(1000);
    myButton.Content="Done";
}

相当于

myButton.Click+=ButtonHandler;

async void ButtonHandler(object sender,EventArgs args)
{
    await Task.Delay(1000);
    myButton.Content="Done";
}
static async Task Main(string[] args)
{
    Funcint>> unnamed = async () =>
    {
        await Task.Delay(1000);
        return 123;
    };
    int answer = await unnamed();
}

异步函数 结束

Original: https://www.cnblogs.com/Leo_wl/p/16521250.html
Author: HackerVirus
Title: 异步函数

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/547297/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球