异步编程和多线程有什么区别? [英] What is the difference between asynchronous programming and multithreading?

查看:25
本文介绍了异步编程和多线程有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为它们基本上是一样的——编写在处理器之间拆分任务的程序(在具有 2 个以上处理器的机器上).然后我正在阅读 this,其中说:

I thought that they were basically the same thing — writing programs that split tasks between processors (on machines that have 2+ processors). Then I'm reading this, which says:

异步方法旨在成为非阻塞操作.等待异步方法中的表达式不会阻塞当前线程,而等待的任务正在运行.相反,表达式签署了其余的方法作为延续并将控制返回给调用者异步方法.

Async methods are intended to be non-blocking operations. An await expression in an async method doesn’t block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method.

async 和 await 关键字不会导致额外的线程创建.异步方法不需要多线程,因为异步方法不在自己的线程上运行.该方法在当前运行同步上下文并仅在线程上使用时间方法是主动的.您可以使用 Task.Run 将受 CPU 限制的工作移至后台线程,但后台线程对进程没有帮助这只是在等待结果可用.

The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active. You can use Task.Run to move CPU-bound work to a background thread, but a background thread doesn't help with a process that's just waiting for results to become available.

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

and I'm wondering whether someone can translate that to English for me. It seems to draw a distinction between asyncronicity (is that a word?) and threading and imply that you can have a program that has asynchronous tasks but no multithreading.

现在我明白了异步任务的想法,比如 pg 上的例子.Jon Skeet 的 C# In Depth,第三版的第 467 页

Now I understand the idea of asynchronous tasks such as the example on pg. 467 of Jon Skeet's C# In Depth, Third Edition

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 关键字的意思是这个函数无论何时被调用,都不会在一个上下文中被调用,在该上下文中,调用后的所有内容都需要完成."

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

In other words, writing it in the middle of some task

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

,由于 DisplayWebsiteLength()xy 无关,将导致 DisplayWebsiteLength()将在后台"执行,例如

, since DisplayWebsiteLength() has nothing to do with x or y, will cause DisplayWebsiteLength() to be executed "in the background", like

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

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

Obviously that's a stupid example, but am I correct or am I totally confused or what?

(另外,我很困惑为什么 sendere 从未在上述函数的主体中使用过.)

(Also, I'm confused about why sender and e aren't ever used in the body of the above function.)

推荐答案

您的误解非常普遍.许多人被教导说多线程和异步是一回事,但事实并非如此.

Your misunderstanding is extremely common. Many people are taught that multithreading and asynchrony are the same thing, but they are not.

类比通常会有所帮助.你在餐厅做饭.一份鸡蛋和吐司的订单进来了.

An analogy usually helps. You are cooking in a restaurant. An order comes in for eggs and toast.

  • 同步:先煮鸡蛋,然后烤吐司.
  • 异步、单线程:您开始煮鸡蛋并设置计时器.您开始烤面包,并设置一个计时器.当他们都在做饭时,你打扫厨房.当计时器响起时,您将鸡蛋从火上移开,将吐司从烤面包机中取出,然后端上来.
  • 异步、多线程:您再雇佣两名厨师,一名负责煮鸡蛋,一名负责烤面包.现在您有协调厨师的问题,以便他们在共享资源时不会在厨房中相互冲突.你必须付钱给他们.

现在多线程只是一种异步有意义吗?线程是关于工人的;异步是关于任务.在多线程工作流中,您将任务分配给工作人员.在异步单线程工作流中,您有一个任务图,其中一些任务依赖于其他任务的结果;当每个任务完成时,它会根据刚刚完成的任务的结果调用安排下一个可以运行的任务的代码.但是您(希望)只需要一名工人来执行所有任务,而不是每个任务一名工人.

Now does it make sense that multithreading is only one kind of asynchrony? Threading is about workers; asynchrony is about tasks. In multithreaded workflows you assign tasks to workers. In asynchronous single-threaded workflows you have a graph of tasks where some tasks depend on the results of others; as each task completes it invokes the code that schedules the next task that can run, given the results of the just-completed task. But you (hopefully) only need one worker to perform all the tasks, not one worker per task.

认识到许多任务不受处理器限制会有所帮助.对于受处理器约束的任务,雇佣与处理器数量一样多的工人(线程),为每个工人分配一项任务,为每个工人分配一个处理器,并让每个处理器只做计算结果的工作是有意义的尽快.但是对于不等待处理器的任务,您根本不需要分配工作人员.您只需等待结果可用的消息到达,然后在等待期间做其他事情.当该消息到达时,您可以将已完成任务的延续安排为待办事项列表中的下一件要核对的事情.

It will help to realize that many tasks are not processor-bound. For processor-bound tasks it makes sense to hire as many workers (threads) as there are processors, assign one task to each worker, assign one processor to each worker, and have each processor do the job of nothing else but computing the result as quickly as possible. But for tasks that are not waiting on a processor, you don't need to assign a worker at all. You just wait for the message to arrive that the result is available and do something else while you're waiting. When that message arrives then you can schedule the continuation of the completed task as the next thing on your to-do list to check off.

那么让我们更详细地看一下 Jon 的例子.发生什么了?

So let's look at Jon's example in more detail. What happens?

  • 有人调用 DisplayWebSiteLength.WHO?我们不在乎.
  • 它设置一个标签,创建一个客户端,并要求客户端获取一些东西.客户端返回一个对象,表示获取某物的任务.该任务正在进行中.
  • 是否正在另一个线程上进行?可能不是.阅读Stephen 的文章,了解为什么没有线程.
  • 现在我们等待任务.发生什么了?我们检查任务是否在我们创建它和我们等待它之间完成.如果是,那么我们获取结果并继续运行.让我们假设它还没有完成.我们将此方法的其余部分注册为该任务的继续并返回.
  • 现在控制权已返回给调用者.它有什么作用?随心所欲.
  • 现在假设任务完成.它是怎么做到的?也许它正在另一个线程上运行,或者我们刚刚返回的调用者允许它在当前线程上运行完成.无论如何,我们现在已经完成了一项任务.
  • 已完成的任务要求正确的线程——同样,可能是唯一线程——运行任务的延续.
  • 控制立即传回我们刚刚离开的方法.现在有 可用的结果,因此我们可以分配 text 并运行该方法的其余部分.
  • Someone invokes DisplayWebSiteLength. Who? We don't care.
  • It sets a label, creates a client, and asks the client to fetch something. The client returns an object representing the task of fetching something. That task is in progress.
  • Is it in progress on another thread? Probably not. Read Stephen's article on why there is no thread.
  • Now we await the task. What happens? We check to see if the task has completed between the time we created it and we awaited it. If yes, then we fetch the result and keep running. Let's suppose it has not completed. We sign up the remainder of this method as the continuation of that task and return.
  • Now control has returned to the caller. What does it do? Whatever it wants.
  • Now suppose the task completes. How did it do that? Maybe it was running on another thread, or maybe the caller that we just returned to allowed it to run to completion on the current thread. Regardless, we now have a completed task.
  • The completed task asks the correct thread -- again, likely the only thread -- to run the continuation of the task.
  • Control passes immediately back into the method we just left at the point of the await. Now there is a result available so we can assign text and run the rest of the method.

就像我的比喻一样.有人要你要一份文件.您通过邮件将文档发送出去,然后继续做其他工作.当它通过邮件到达时,您会收到信号,当您愿意时,您就可以完成其余的工作流程——打开信封、支付递送费用等等.您无需雇用其他员工来为您完成所有这些工作.

It's just like in my analogy. Someone asks you for a document. You send away in the mail for the document, and keep on doing other work. When it arrives in the mail you are signalled, and when you feel like it, you do the rest of the workflow -- open the envelope, pay the delivery fees, whatever. You don't need to hire another worker to do all that for you.

这篇关于异步编程和多线程有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆