异步编程和多线程有什么区别?

异步编程和多线程有什么区别?

我认为它们基本上是相同的 - 编写在处理器之间分割任务的程序(在具有2个以上处理器的机器上)。然后我正在阅读https://msdn.microsoft.com/en-us/library/hh191443.aspx,其中说

异步方法旨在实现非阻塞操作。在等待任务运行时,异步方法中的await表达式不会阻止当前线程。相反,表达式将方法的其余部分作为延续进行注册,并将控制权返回给异步方法的调用者。

async和await关键字不会导致创建其他线程。异步方法不需要多线程,因为异步方法不能在自己的线程上运行。该方法在当前同步上下文上运行,并仅在方法处于活动状态时在线程上使用时间。您可以使用Task.Run将CPU绑定的工作移动到后台线程,但后台线程无助于只等待结果可用的进程。

我想知道是否有人可以为我翻译成英文。它似乎区分了异步性(是一个单词?)和线程,并暗示你可以拥有一个具有异步任务但没有多线程的程序。

现在我理解异步任务的想法,例如pg上的示例。Jon Skeet的C#In Depth,第三版中的 467

async void DisplayWebsiteLength ( object sender, EventArgs e ){
    label.Text = "Fetching ...";
    using ( HttpClient client = new HttpClient() )
    {
        Task<string> task = client.GetStringAsync("http://csharpindepth.com");
        string text = await task;
        label.Text = text.Length.ToString();
    }}

async关键字的意思是“ 这个功能,无论何时它被调用时,不会在这是需要的一切它的完成被称为它的呼叫后,上下文调用。”

换句话说,将它写在某个任务的中间

int x = 5; DisplayWebsiteLength();double y = Math.Pow((double)x,2000.0);

,因为DisplayWebsiteLength()与“无关” xy将导致DisplayWebsiteLength()“在后台”执行,如

                processor 1                |      processor 2-------------------------------------------------------------------int x = 5;                                 |  DisplayWebsiteLength()double y = Math.Pow((double)x,2000.0);     |

显然这是一个愚蠢的例子,但我是正确还是我完全困惑或者是什么?

(另外,我很困惑为什么sendere并且从未在上述功能的主体中使用过。)


幕布斯7119047
浏览 1439回答 2
2回答

元芳怎么了

浏览器内的Javascript是没有线程的异步程序的一个很好的例子。您不必担心同时触摸相同对象的多个代码片段:在允许任何其他javascript在页面上运行之前,每个函数都将完成运行。但是,当执行类似AJAX请求的操作时,根本没有代码运行,因此其他javascript可以响应点击事件之类的事情,直到该请求返回并调用与之关联的回调。如果其中一个其他事件处理程序在AJAX请求返回时仍在运行,则在完成之前不会调用其处理程序。只有一个JavaScript“线程”在运行,即使你有可能有效地暂停你正在做的事情,直到你得到你需要的信息。在C#应用程序中,每当您处理UI元素时都会发生同样的事情 - 当您在UI线程上时,您只能与UI元素进行交互。如果用户单击了一个按钮,并且您希望通过从磁盘读取大文件来进行响应,那么没有经验的程序员可能会错误地在单击事件处理程序本身内读取该文件,这会导致应用程序“冻结”直到文件已完成加载,因为在释放该线程之前,不允许再响应任何更多点击,悬停或任何其他与UI相关的事件。程序员可能会使用一个选项来避免这个问题,就是创建一个新的线程来加载文件,然后告诉该线程的代码,当文件加载时,它需要再次运行UI线程上的剩余代码,以便它可以更新UI元素基于它在文件中找到的内容。直到最近,这种方法非常受欢迎,因为它使C#库和语言变得容易,但它从根本上说比它复杂得多。如果你考虑CPU在硬件/操作系统级别读取文件时所做的事情,它基本上会发出一条指令,将磁盘中的数据从内存读入内存,并在发出“中断”时触发操作系统。读完了。换句话说,从磁盘(或任何I / O)读取是一种固有的异步操作。等待I / O完成的线程的概念是库开发人员创建的抽象,以便更容易编程。这不是必需的。现在,.NET中的大多数I / O操作都有一个...Async()可以调用的相应方法,它Task几乎立即返回。您可以向此添加回调以Task指定在异步操作完成时要运行的代码。您还可以指定要运行该代码的线程,并且可以提供异步操作可以不时检查的令牌,以确定您是否决定取消异步任务,从而使其有机会快速停止其工作优雅地在async/await添加关键字之前,C#对于如何调用回调代码更为明显,因为这些回调采用与任务关联的委托形式。为了仍然为您提供使用该...Async()操作的好处,同时避免代码的复杂性,async/await抽象出这些代理的创建。但它们仍然存在于已编译的代码中。因此,您可以让您的UI事件处理程序await进行I / O操作,释放UI线程以执行其他操作,并在读完文件后自动返回UI线程 - 无需创建一个新线程。
打开App,查看更多内容
随时随地看视频慕课网APP