代码之家  ›  专栏  ›  技术社区  ›  Imad

异步方法正在串行执行[重复]

  •  0
  • Imad  · 技术社区  · 6 年前

    从我的理解来看 async and await

    我正在尝试最基本的例子。我在内联中添加了一些评论。你能为我澄清一下吗?

    // I don't understand why this method must be marked as `async`.
    private async void button1_Click(object sender, EventArgs e)
    {
        Task<int> access = DoSomethingAsync();
        // task independent stuff here
    
        // this line is reached after the 5 seconds sleep from 
        // DoSomethingAsync() method. Shouldn't it be reached immediately? 
        int a = 1; 
    
        // from my understanding the waiting should be done here.
        int x = await access; 
    }
    
    async Task<int> DoSomethingAsync()
    {
        // is this executed on a background thread?
        System.Threading.Thread.Sleep(5000);
        return 1;
    }
    
    0 回复  |  直到 6 年前
        1
  •  741
  •   Dan Dinu    7 年前

    使用时 async await 编译器在后台生成一个状态机。

    下面是一个例子,我希望我可以解释一些正在进行的高级细节:

    public async Task MyMethodAsync()
    {
        Task<int> longRunningTask = LongRunningOperationAsync();
        // independent work which doesn't need the result of LongRunningOperationAsync can be done here
    
        //and now we call await on the task 
        int result = await longRunningTask;
        //use the result 
        Console.WriteLine(result);
    }
    
    public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation 
    {
        await Task.Delay(1000); // 1 second delay
        return 1;
    }
    

    1. Task<int> longRunningTask = LongRunningOperationAsync(); 开始执行 LongRunningOperation

    2. 独立的工作是在假设主线程(线程ID=1)上完成的,然后 await longRunningTask 已到达。

      现在,如果 longRunningTask 还没完成,还在运行, MyMethodAsync() 长跑任务 完成后,来自线程池的线程(可以是任何线程)将返回到 MyMethodAsync() 在其上一个上下文中并继续执行(在本例中,将结果打印到控制台)。

    第二种情况是 长跑任务 等待长时间运行任务 我们已经得到了结果,所以代码将继续在同一个线程上执行。(在这种情况下,将结果打印到控制台)。当然,上面的例子不是这样的 Task.Delay(1000)

        2
  •  166
  •   AleksanderCH    6 年前

    根据我的理解,async和await的主要功能之一是使代码易于编写和读取。

    他们要 异步的 代码易于编写和阅读,是的。

    一点也不。

    //我不明白为什么这个方法必须标记为“async”。

    async 关键字启用 await 关键字。所以任何使用 必须标记 .

    //在DoSomethingAsync()方法休眠5秒后到达该行。不应该马上联系吗?

    不,因为 默认情况下,方法不在其他线程上运行。

    //这是在后台线程上执行的吗?


    你可以找到我的 async / await intro official MSDN docs 也非常好(特别是 TAP 部分),以及 异步 FAQ .

        3
  •  163
  •   Eliahu Aaron Guru Stron    5 年前

    下面是一个简单的例子 async / await

    注: Task.Delay(1000) 模拟工作1秒。我认为最好将此视为等待外部资源的响应。因为我们的代码正在等待响应,所以系统可以将正在运行的任务设置为side,并在完成后返回到它。同时,它还可以在这个线程上做一些其他工作。

    在下面的示例中 第一个街区 就是这么做的。它立即开始所有的任务 Task.Delay 线)并将它们放在一边。代码将在 await a b , c , d ,和 e 所有人几乎都是在 a (由于缺少等待),在这种情况下,他们应该在大致相同的时间完成。

    在下面的示例中 第二个街区 开始一项任务并等待它完成(这就是 等待 在开始后续任务之前。每次迭代需要1秒。这个 正在暂停程序并等待结果,然后继续。这是第一块和第二块的主要区别。

    例子

    Console.WriteLine(DateTime.Now);
    
    // This block takes 1 second to run because all
    // 5 tasks are running simultaneously
    {
        var a = Task.Delay(1000);
        var b = Task.Delay(1000);
        var c = Task.Delay(1000);
        var d = Task.Delay(1000);
        var e = Task.Delay(1000);
    
        await a;
        await b;
        await c;
        await d;
        await e;
    }
    
    Console.WriteLine(DateTime.Now);
    
    // This block takes 5 seconds to run because each "await"
    // pauses the code until the task finishes
    {
        await Task.Delay(1000);
        await Task.Delay(1000);
        await Task.Delay(1000);
        await Task.Delay(1000);
        await Task.Delay(1000);
    }
    Console.WriteLine(DateTime.Now);
    

    5/24/2017 2:22:50 PM
    5/24/2017 2:22:51 PM (First block took 1 second)
    5/24/2017 2:22:56 PM (Second block took 5 seconds)
    

    有关同步上下文的额外信息

    注意:这里的情况对我来说有点模糊,所以如果我做错了什么,请纠正我,我会更新答案。对它的工作原理有一个基本的了解是很重要的,但是只要你从不使用它,你就可以不用成为它的专家 ConfigureAwait(false)

    这其中有一个方面使得 异步 / 这个概念比较难理解。事实上,在这个例子中,这一切都发生在同一个线程上(或者至少在它的 SynchronizationContext ). 默认情况下, 将还原在其上运行的原始线程的同步上下文。例如,在ASP.NET中 HttpContext 请求上下文 这可能是灾难性的。如果你知道你不会将上下文用于任何事情,你可以选择“不关心”它。这基本上允许您的代码在一个单独的线程上运行,而不必带上上下文。

    await a; 代码实际上是假设您确实要捕获和还原上下文:

    await a; //Same as the line below
    await a.ConfigureAwait(true);
    

    如果希望允许主代码在没有原始上下文的新线程上继续,只需使用false而不是true,这样它就知道不需要恢复上下文。

    await a.ConfigureAwait(false);
    

    程序完成暂停后,它将继续 在一个完全不同的线程上,有不同的上下文。这就是性能改进的来源——它可以在任何可用的线程上继续,而不必恢复它开始时的原始上下文。

    这东西让人困惑吗?是啊!你能搞清楚吗?可能!一旦你掌握了这些概念,那么继续斯蒂芬·克利里的解释,这些解释往往更倾向于那些对 异步 / 等待 已经。

        4
  •  147
  •   Federico Dipuma    7 年前

    在其他答案的基础上,看一看 await (C# Reference)

    下面的Windows窗体示例演示了在 异步方法,WaitAsynchronouslyAsync。对比一下他们的行为 运算符应用于任务,WaitSynchronously运行 尽管在定义中使用了async修饰符并调用了 线。睡在它的身体里。

    private async void button1_Click(object sender, EventArgs e)
    {
        // Call the method that runs asynchronously.
        string result = await WaitAsynchronouslyAsync();
    
        // Call the method that runs synchronously.
        //string result = await WaitSynchronously ();
    
        // Display the result.
        textBox1.Text += result;
    }
    
    // The following method runs asynchronously. The UI thread is not
    // blocked during the delay. You can move or resize the Form1 window 
    // while Task.Delay is running.
    public async Task<string> WaitAsynchronouslyAsync()
    {
        await Task.Delay(10000);
        return "Finished";
    }
    
    // The following method runs synchronously, despite the use of async.
    // You cannot move or resize the Form1 window while Thread.Sleep
    // is running because the UI thread is blocked.
    public async Task<string> WaitSynchronously()
    {
        // Add a using directive for System.Threading.
        Thread.Sleep(10000);
        return "Finished";
    }
    
        5
  •  59
  •   Eliahu Aaron Guru Stron    5 年前

    在一个简单的控制台程序中显示上述说明:

    class Program
    {
        static void Main(string[] args)
        {
            TestAsyncAwaitMethods();
            Console.WriteLine("Press any key to exit...");
            Console.ReadLine();
        }
    
        public async static void TestAsyncAwaitMethods()
        {
            await LongRunningMethod();
        }
    
        public static async Task<int> LongRunningMethod()
        {
            Console.WriteLine("Starting Long Running method...");
            await Task.Delay(5000);
            Console.WriteLine("End Long Running method...");
            return 1;
        }
    }
    

    结果是:

    Starting Long Running method...
    Press any key to exit...
    End Long Running method...
    

    因此,

    1. TestAsyncAwaitMethods . 立即返回而不停止当前线程,我们立即看到“按任意键退出”消息
    2. 一直以来 LongRunningMethod

    因此,没有线程被阻塞。

        6
  •  41
  •   Druid    9 年前

    System.Threading.Thread.Sleep

    一点 async 任务是让它在后台执行而不锁定主线程,例如 DownloadFileAsync

    不是“正在做”的事情,它只是睡觉,因此5秒后到达下一行。。。

    读这篇文章,我认为它是对 异步 await 概念: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx

        7
  •  21
  •   Eliahu Aaron Guru Stron    5 年前

    下面是一个快速的控制台程序,可以让后面的人看清楚。这个 TaskToDo 方法是要使其异步的长时间运行的方法。使其运行异步是由 TestAsync 方法。test loops方法只是通过 任务并异步运行它们。您可以在结果中看到这一点,因为它们从运行到运行的顺序不同—它们在完成时会向控制台UI线程报告。简单化,但我认为简单化的例子比更复杂的例子更能揭示模式的核心:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace TestingAsync
    {
        class Program
        {
            static void Main(string[] args)
            {
                TestLoops();
                Console.Read();
            }
    
            private static async void TestLoops()
            {
                for (int i = 0; i < 100; i++)
                {
                    await TestAsync(i);
                }
            }
    
            private static Task TestAsync(int i)
            {
                return Task.Run(() => TaskToDo(i));
            }
    
            private async static void TaskToDo(int i)
            {
                await Task.Delay(10);
                Console.WriteLine(i);
            }
        }
    }
    
        8
  •  15
  •   Eliahu Aaron Guru Stron    5 年前

    这里所有的答案都是 Task.Delay() 或者其他内置的 async 功能。但这里是我的例子 异步 功能:

    // Starts counting to a large number and then immediately displays message "I'm counting...". 
    // Then it waits for task to finish and displays "finished, press any key".
    static void asyncTest ()
    {
        Console.WriteLine("Started asyncTest()");
        Task<long> task = asyncTest_count();
        Console.WriteLine("Started counting, please wait...");
        task.Wait(); // if you comment this line you will see that message "Finished counting" will be displayed before we actually finished counting.
        //Console.WriteLine("Finished counting to " + task.Result.ToString()); // using task.Result seems to also call task.Wait().
        Console.WriteLine("Finished counting.");
        Console.WriteLine("Press any key to exit program.");
        Console.ReadLine();
    }
    
    static async Task<long> asyncTest_count()
    {
        long k = 0;
        Console.WriteLine("Started asyncTest_count()");
        await Task.Run(() =>
        {
            long countTo = 100000000;
            int prevPercentDone = -1;
            for (long i = 0; i <= countTo; i++)
            {
                int percentDone = (int)(100 * (i / (double)countTo));
                if (percentDone != prevPercentDone)
                {
                    prevPercentDone = percentDone;
                    Console.Write(percentDone.ToString() + "% ");
                }
    
                k = i;
            }
        });
        Console.WriteLine("");
        Console.WriteLine("Finished asyncTest_count()");
        return k;
    }
    
        9
  •  12
  •   Lex Li    10 年前

    这个答案旨在提供一些特定于ASP.NET的信息。

    通过在MVC控制器中使用async/await,可以提高线程池的利用率并获得更好的吞吐量,如下文所述,

    http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

    在web应用程序中,在 启动或负荷过大(并发性突然增加), 使这些web服务调用异步将增加 申请的响应性。异步请求接受 如果请求发出需要两秒钟 完成,请求是否执行需要两秒钟 线程在响应其他请求时未被阻止 等待第一个请求完成。因此,异步 许多调用长时间运行操作的并发请求。

        10
  •  10
  •   Hakim    6 年前

    异步/等待

    实际上Async/Await是一对关键字,它们只是创建异步任务回调的语法糖。

    以该操作为例:

        public static void DoSomeWork()
        {
            var task = Task.Run(() =>
            {
                // [RUNS ON WORKER THREAD]
    
                // IS NOT bubbling up due to the different threads
                throw new Exception();
                Thread.Sleep(2000);
    
                return "Hello";
            });
    
            // This is the callback
            task.ContinueWith((t) => {
                // -> Exception is swallowed silently
                Console.WriteLine("Completed");
    
                // [RUNS ON WORKER THREAD]
            });
        }
    

    上面的代码有几个缺点。错误不会传递,而且很难阅读。 但是Async等着进来帮我们:

        public async static void DoSomeWork()
        {
            var result = await Task.Run(() =>
            {
                // [RUNS ON WORKER THREAD]
    
                // IS bubbling up
                throw new Exception();
                Thread.Sleep(2000);
    
                return "Hello";
            });
    
            // every thing below is a callback 
            // (including the calling methods)
    
            Console.WriteLine("Completed");
    
        }
    

    • 返回任务的结果
    • 检查错误并让它们在callstack中冒泡(在callstack中最多只有无等待调用)
    • 等待结果
    • 释放主线
    • 在主线程上运行回调
    • 使用线程池中的工作线程执行任务
    • 使代码易于阅读

    注意 具有 异步调用 任务库

    下面是等待和不等待解决方案的比较

        public static long DoTask()
        {
            stopWatch.Reset();
            stopWatch.Start();
    
            // [RUNS ON MAIN THREAD]
            var task = Task.Run(() => {
                Thread.Sleep(2000);
                // [RUNS ON WORKER THREAD]
            });
            // goes directly further
            // WITHOUT waiting until the task is finished
    
            // [RUNS ON MAIN THREAD]
    
            stopWatch.Stop();
            // 50 milliseconds
            return stopWatch.ElapsedMilliseconds;
        }
    

    这是异步方法:

        public async static Task<long> DoAwaitTask()
        {
            stopWatch.Reset();
            stopWatch.Start();
    
            // [RUNS ON MAIN THREAD]
    
            await Task.Run(() => {
                Thread.Sleep(2000);
                // [RUNS ON WORKER THREAD]
            });
            // Waits until task is finished
    
            // [RUNS ON MAIN THREAD]
    
            stopWatch.Stop();
            // 2050 milliseconds
            return stopWatch.ElapsedMilliseconds;
        }
    

    实际上,您可以在不使用await关键字的情况下调用异步方法,但这意味着这里的任何异常都会在释放模式下被吞噬:

        public static Stopwatch stopWatch { get; } = new Stopwatch();
    
        static void Main(string[] args)
        {
            Console.WriteLine("DoAwaitTask: " + DoAwaitTask().Result + " ms");
            // 2050 (2000 more because of the await)
            Console.WriteLine("DoTask: " + DoTask() + " ms");
            // 50
            Console.ReadKey();
        }
    

    异步和等待不适用于并行计算。它们是用来不堵住你的主线的。当涉及到asp.net或Windows应用程序时,由于网络调用而阻塞主线程是一件坏事。如果你这样做,你的应用程序将得到无响应,甚至崩溃。

    ms docs 更多的例子。

        11
  •  10
  •   Blue Clouds    5 年前

    快速学习。。

    • 问题反思(学习目的):1分钟

    • 快速通过语法sugar:5分钟

    • 问题:快速将现实世界中正常代码的实现更改为

    • 下一个在哪里?

    在这张图片中,只关注#6(没有更多) enter image description here

    在第6步:执行停止,因为它已经用完了工作。要继续,需要getStringTask(某种函数)的结果。因此,它使用 await 操作员暂停其进程并将控制权还给调用者。对getStringTask的实际调用是在#2的前面进行的。它将任务(字符串返回值)传递给调用方。该任务表示生成字符串结果的承诺。 但它什么时候会回电话呢?我们应该(访问webasync)再打第二次电话吗?谁得到结果,#2(调用语句)或#6(等待语句)

    这是“异步”的最大优点!

    任务! 任务已通过。 等待任务 (不是方法,不是价值)。值将在任务中设置。任务状态将设置为“完成”。呼叫方只监视任务(#6)。后续阅读 here

    学习问题反思:1分钟

    如何及何时使用 async 等待 Tasks ?

    因为学习 Task

    快速通过语法sugar:5分钟

    • 转换前(原方法)

      internal static int Method(int arg0, int arg1) { int result = arg0 + arg1; IO(); // Do some long running IO. return result; }

    • internal static Task<int> MethodTask(int arg0, int arg1) { Task<int> task = new Task<int>(() => Method(arg0, arg1)); task.Start(); // Hot task (started task) should always be returned. return task; }

    我们提到等待还是异步?不,调用上面的方法,你就会得到一个任务。你可以监控。你已经知道任务返回了什么。。一个整数。

    • internal static async Task<int> MethodAsync(int arg0, int arg1) { int result = await HelperMethods.MethodTask(arg0, arg1); return result; }

    上面添加的代码与下面的图片相同: enter image description here

    1. 等待
    2. 异步 (强制语法)
    3. Async 作为前缀(编码标准)

    等待 异步 , 异步 )可能不是:)。不过,对编译器来说应该更有意义 here

    所以有两部分。

    1. 创建“任务”
    2. await+async )

    请记住,我们有一个外部调用程序来访问webasync(),该调用程序也不能幸免;)。i、 它需要同样的东西 等待+异步 我也是。链条还在继续。但总会有 在一端。

    失踪。。。

    开发人员犯了一个错误,没有实现 任务 provided here . 希望您已经阅读并完全理解。总结是,我们可能看不到/实现“Task”,但它是在父类的某个地方实现的。同样地,在我们的示例中调用 MethodAsync() 比用 任务 ( MethodTask() )我们自己。大多数开发人员发现很难让自己的头脑清醒起来 任务 同时将代码转换为异步代码。

    提示:尝试查找现有的异步实现(如 MethodAsync ToListAsync )把困难外包出去。所以我们只需要处理Async和await(这很简单,与普通代码非常相似)

    问题:快速将现实世界中正常代码的实现更改为 异步操作:2分钟

    var myContract = query.Where(c => c.ContractID == _contractID).First();
    

    轻松!

    1. 我们安装了EntityFrameWork nuget包,因为它具有QueryableExtensions。或者换句话说,它执行异步实现(task),这样我们就可以通过简单的 等待 在密码里。
    2. 命名空间=Microsoft.EntityFrameworkCore

    调用代码行的更改如下

    var myContract = await query.Where(c => c.ContractID == _contractID).FirstAsync();
    
    1. Contract GetContract(int contractnumber)

      async Task<Contract> GetContractAsync(int contractnumber)

    2. 调用方法也受到影响: GetContractAsync(123456); GetContractAsync(123456).Result;

    3. 我们在30分钟内到处都换了!

    下一个在哪里? 我们可以看一段精彩的视频 Converting Synchronous Calls to Asynchronous in ASP.Net Core

        12
  •  9
  •   atlaste    12 年前

    老实说,我仍然认为最好的解释是关于未来和维基百科上的承诺: http://en.wikipedia.org/wiki/Futures_and_promises

    基本思想是,您有一个单独的线程池,可以异步执行任务。使用时。但是,该对象承诺它将在某个时间执行操作,并在您请求时提供结果。这意味着,当您请求结果但尚未完成时,它将被阻塞,否则将在线程池中执行。

    从那里你可以优化一些事情:一些操作可以异步实现,你可以通过批量处理后续请求和/或重新排序来优化文件IO和网络通信等事情。我不确定这是否已经在微软的任务框架中,但如果不是,这将是我要添加的第一件事。

    实际上,你可以在C#4.0中用收益率实现未来的模式。如果你想知道它是如何工作的,我可以推荐这个链接做一个体面的工作: http://code.google.com/p/fracture/source/browse/trunk/Squared/TaskLib/

        13
  •  8
  •   vibs2006    7 年前

    看这个小提琴 https://dotnetfiddle.net/VhZdLU (并在可能的情况下加以改进)用于运行 它显示了 Task,Task.WaitAll(),异步和等待 同一程序中的运算符。

    这把小提琴应该能清楚你的执行周期概念。

    这是示例代码

    using System;
    using System.Threading.Tasks;
    
    public class Program
    {
        public static void Main()
        {               
            var a = MyMethodAsync(); //Task started for Execution and immediately goes to Line 19 of the code. Cursor will come back as soon as await operator is met       
            Console.WriteLine("Cursor Moved to Next Line Without Waiting for MyMethodAsync() completion");
            Console.WriteLine("Now Waiting for Task to be Finished");       
            Task.WaitAll(a); //Now Waiting      
            Console.WriteLine("Exiting CommandLine");       
        }
    
        public static async Task MyMethodAsync()
        {
            Task<int> longRunningTask = LongRunningOperation();
            // independent work which doesn't need the result of LongRunningOperationAsync can be done here
            Console.WriteLine("Independent Works of now executes in MyMethodAsync()");
            //and now we call await on the task 
            int result = await longRunningTask;
            //use the result 
            Console.WriteLine("Result of LongRunningOperation() is " + result);
        }
    
        public static async Task<int> LongRunningOperation() // assume we return an int from this long running operation 
        {
            Console.WriteLine("LongRunningOperation() Started");
            await Task.Delay(2000); // 2 second delay
            Console.WriteLine("LongRunningOperation() Finished after 2 Seconds");
            return 1;
        }   
    
    }
    

    来自输出窗口的跟踪: enter image description here

        14
  •  7
  •   James Mallon    5 年前

    异步等待简单解释

    一个人可以 早上的火车。这是他们正在做的一切,因为这是他们目前正在执行的主要任务。(同步编程(您通常所做的!)

    另一个人可以 等待

    什么是异步编程?

    async关键字实际上是做什么的?

    在方法名前面加上async关键字,如

    async void DoSomething(){ . . .
    

    为什么这很重要?

    在许多软件系统中,主线程是专门用于与用户界面相关的操作的。如果我在我的计算机上运行一个非常复杂的递归算法,需要5秒才能完成,但是当用户试图单击我的应用程序上的任何内容时,我在主线程(UI线程)上运行这个算法,它将看起来被冻结,因为我的主线程已经排队,并且当前正在处理太多的操作。因此,主线程无法处理鼠标单击以从按钮单击运行方法。

    什么时候使用异步等待?

    理想情况下,当您做任何不涉及用户界面的事情时,请使用异步关键字。

    假设你正在编写一个程序,允许用户在手机上画草图,但每5秒它就会在互联网上查看天气。

    我们应该每5秒等待一次投票呼叫,以获取网络的天气,因为应用程序的用户需要不断与移动触摸屏交互以绘制漂亮的图片。

    如何使用Async和wait

    下面是上面的示例,下面是一些如何编写它的伪代码:

        //ASYNCHRONOUS
        //this is called using the await keyword every 5 seconds from a polling timer or something.
    
        async Task CheckWeather()
        {
            var weather = await GetWeather();
            //do something with the weather now you have it
        }
    
        async Task<WeatherResult> GetWeather()
        {
    
            var weatherJson = await CallToNetworkAddressToGetWeather();
            return deserializeJson<weatherJson>(weatherJson);
        }
    
        //SYNCHRONOUS
        //This method is called whenever the screen is pressed
        void ScreenPressed()
        {
            DrawSketchOnScreen();
        }
    

    附加说明-更新

    // awaiting this will return a string.
    // calling this without await (synchronously) will result in a Task<string> object.
    async Task<string> FetchHelloWorld() {..
    

    不能等待不是以下任务的方法:

    async string FetchHelloWorld() {..
    

    请随意查看任务类的源代码 here .

        15
  •  3
  •   Weslley Rufino de Lima    7 年前
    public static void Main(string[] args)
    {
        string result = DownloadContentAsync().Result;
        Console.ReadKey();
    }
    
    // You use the async keyword to mark a method for asynchronous operations.
    // The "async" modifier simply starts synchronously the current thread. 
    // What it does is enable the method to be split into multiple pieces.
    // The boundaries of these pieces are marked with the await keyword.
    public static async Task<string> DownloadContentAsync()// By convention, the method name ends with "Async
    {
        using (HttpClient client = new HttpClient())
        {
            // When you use the await keyword, the compiler generates the code that checks if the asynchronous operation is finished.
            // If it is already finished, the method continues to run synchronously.
            // If not completed, the state machine will connect a continuation method that must be executed WHEN the Task is completed.
    
    
            // Http request example. 
            // (In this example I can set the milliseconds after "sleep=")
            String result = await client.GetStringAsync("http://httpstat.us/200?sleep=1000");
    
            Console.WriteLine(result);
    
            // After completing the result response, the state machine will continue to synchronously execute the other processes.
    
    
            return result;
        }
    }
    
        16
  •  3
  •   ABajpai    6 年前

    在更高的层次上:

    2) 您可以等待返回任务或T类型任务的方法。不能等待异步void方法。

    4) 如果主线程看到仍在执行的任务上有wait,则它不会等待它并返回到当前方法的调用方。这样,应用程序保持响应。

    5) 等待处理任务,现在将在线程池中的单独线程上执行。

    6) 当这个等待任务完成时,下面的所有代码将由单独的线程执行

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace AsyncAwaitDemo
    {
        class Program
        {
            public static async void AsynchronousOperation()
            {
                Console.WriteLine("Inside AsynchronousOperation Before AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                //Task<int> _task = AsyncMethod();
                int count = await AsyncMethod();
    
                Console.WriteLine("Inside AsynchronousOperation After AsyncMethod Before Await, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
    
                //int count = await _task;
    
                Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await Before DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
    
                DependentMethod(count);
    
                Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await After DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
            }
    
            public static async Task<int> AsyncMethod()
            {
                Console.WriteLine("Inside AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                int count = 0;
    
                await Task.Run(() =>
                {
                    Console.WriteLine("Executing a long running task which takes 10 seconds to complete, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(20000);
                    count = 10;
                });
    
                Console.WriteLine("Completed AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
    
                return count;
            }       
    
            public static void DependentMethod(int count)
            {
                Console.WriteLine("Inside DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId + ". Total count is " + count);
            }
    
            static void Main(string[] args)
            {
                Console.WriteLine("Started Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
    
                AsynchronousOperation();
    
                Console.WriteLine("Completed Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
    
                Console.ReadKey();
            }
    
        }
    }
    
        17
  •  2
  •   user21306    7 年前

    我的理解也是,应该在组合中加入第三个术语: Task .

    Async

    任务 async 功能。它异步执行。

    await 任务。当代码执行到达这一行时,控件跳回周围原始函数的调用方。

    如果相反,您将 异步 功能(即 )对于变量,当代码执行到这一行时,它只是 继续 在周围函数中超过该行 虽然 任务 异步执行。

        18
  •  1
  •   Dmitry G.    8 年前

    使用它们等于生成后台线程来执行长 持续时间逻辑?

    本文 MDSN:Asynchronous Programming with async and await (C#) 明确解释:

    async和await关键字不会导致其他线程 创建。异步方法不需要多线程,因为 方法不在自己的线程上运行。该方法在当前 同步上下文并仅在 方法处于活动状态。

        19
  •  1
  •   lazydeveloper    7 年前

    在下面的代码中,HttpClient方法GetByteArrayAsync返回一个任务getContentsTask。任务是在任务完成时生成实际字节数组的承诺。await运算符应用于getContentsTask,以暂停SumPageSizesAsync中的执行,直到getContentsTask完成。同时,控件返回给SumPageSizesAsync的调用方。当getContentsTask完成时,await表达式计算为字节数组。

    private async Task SumPageSizesAsync()
    {
        // To use the HttpClient type in desktop apps, you must include a using directive and add a 
        // reference for the System.Net.Http namespace.
        HttpClient client = new HttpClient();
        // . . .
        Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
        byte[] urlContents = await getContentsTask;
    
        // Equivalently, now that you see how it works, you can write the same thing in a single line.
        //byte[] urlContents = await client.GetByteArrayAsync(url);
        // . . .
    }
    
        20
  •  1
  •   Pang Ajmal PraveeN    6 年前

    namespace EmailBillingRates
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                lblProcessing.Text = "";
            }
    
            private async void btnReadExcel_Click(object sender, EventArgs e)
            {
                string filename = OpenFileDialog();
    
                Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
                Microsoft.Office.Interop.Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(filename);
                Microsoft.Office.Interop.Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[1];
                Microsoft.Office.Interop.Excel.Range xlRange = xlWorksheet.UsedRange;
                try
                {
                    Task<int> longRunningTask = BindGrid(xlRange);
                    int result = await longRunningTask;
    
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message.ToString());
                }
                finally
                {
                    //cleanup  
                   // GC.Collect();
                    //GC.WaitForPendingFinalizers();
    
                    //rule of thumb for releasing com objects:  
                    //  never use two dots, all COM objects must be referenced and released individually  
                    //  ex: [somthing].[something].[something] is bad  
    
                    //release com objects to fully kill excel process from running in the background  
                    Marshal.ReleaseComObject(xlRange);
                    Marshal.ReleaseComObject(xlWorksheet);
    
                    //close and release  
                    xlWorkbook.Close();
                    Marshal.ReleaseComObject(xlWorkbook);
    
                    //quit and release  
                    xlApp.Quit();
                    Marshal.ReleaseComObject(xlApp);
                }
    
            }
    
            private void btnSendEmail_Click(object sender, EventArgs e)
            {
    
            }
    
            private string OpenFileDialog()
            {
                string filename = "";
                OpenFileDialog fdlg = new OpenFileDialog();
                fdlg.Title = "Excel File Dialog";
                fdlg.InitialDirectory = @"c:\";
                fdlg.Filter = "All files (*.*)|*.*|All files (*.*)|*.*";
                fdlg.FilterIndex = 2;
                fdlg.RestoreDirectory = true;
                if (fdlg.ShowDialog() == DialogResult.OK)
                {
                    filename = fdlg.FileName;
                }
                return filename;
            }
    
            private async Task<int> BindGrid(Microsoft.Office.Interop.Excel.Range xlRange)
            {
                lblProcessing.Text = "Processing File.. Please wait";
                int rowCount = xlRange.Rows.Count;
                int colCount = xlRange.Columns.Count;
    
                // dt.Column = colCount;  
                dataGridView1.ColumnCount = colCount;
                dataGridView1.RowCount = rowCount;
    
                for (int i = 1; i <= rowCount; i++)
                {
                    for (int j = 1; j <= colCount; j++)
                    {
                        //write the value to the Grid  
                        if (xlRange.Cells[i, j] != null && xlRange.Cells[i, j].Value2 != null)
                        {
                             await Task.Delay(1);
                             dataGridView1.Rows[i - 1].Cells[j - 1].Value =  xlRange.Cells[i, j].Value2.ToString();
                        }
    
                    }
                }
                lblProcessing.Text = "";
                return 0;
            }
        }
    
        internal class async
        {
        }
    }
    
        21
  •  0
  •   Stephen Marcus    7 年前

    这里的答案可以作为关于等待/异步的一般指导。它们还包含一些关于wait/async如何连接的细节。在使用这种设计模式之前,我想和您分享一些您应该知道的实践经验。

    前景 线程,这是 . 前台线程承担着构建应用程序的负担,包括视图、视图模型、初始动画,以及其他任何与这些元素绑定的东西。所以当你等待前景时 停止

    您当然可以使用各种方法等待后台线程:

    Device.BeginInvokeOnMainThread(async () => { await AnyAwaitableMethod(); });
    
    // Notice that we do not await the following call, 
    // as that would tie it to the foreground thread.
    try
    {
    Task.Run(async () => { await AnyAwaitableMethod(); });
    }
    catch
    {}
    

    这些备注的完整代码位于 https://github.com/marcusts/xamarin-forms-annoyances . 请参阅名为awaitsyncAntipPattern.sln的解决方案。

    GitHub站点还提供了指向有关此主题的更详细讨论的链接。