Threads有多不同的异步编程?

Tar*_*rik 33 .net c# asp.net asynchronous

我一直在async这里阅读一些文章:http://www.asp.net/web-forms/tutorials/aspnet-45/using-asynchronous-methods-in-aspnet-45,作者说:

在进行异步工作时,并不总是使用线程.例如,当您发出异步Web服务请求时,ASP.NET将不会在异步方法调用和await之间使用任何线程.

所以我想要了解的是,async如果我们不使用任何线程进行并发执行,它会如何变成?这是什么意思"你并不总是使用线程."?

让我首先解释一下我对使用线程的了解(一个简单的例子,当然Threads可以在UI和Worker方法之外的其他情况下使用)

  1. 你有UI线程来获取输入,给出输出.
  2. 您可以在UI线程中处理事物,但它会使UI无响应.
  3. 所以我们假设我们有一个与流相关的操作,我们需要下载某种数据.
  4. 我们还允许用户在下载时执行其他操作.
  5. 我们创建一个新的工作线程,下载文件并更改进度条.
  6. 一旦完成,没有任何事情要做,所以线程被杀死.
  7. 我们从UI线程继续.

我们可以根据情况等待UI线程中的工作线程,但在下载文件之前,我们可以使用UI线程做其他事情,然后等待工作线程.

async编程不一样吗?如果没有,有什么区别?我读过async编程ThreadPool用来拉线程.

Ste*_*ary 33

异步编程不需要线程.

"异步"表示API不会阻止调用线程.它并不意味着有另一个线程阻塞.

首先,考虑一下您的UI示例,这次使用实际的异步API:

  1. 你有UI线程来获取输入,给出输出.
  2. 您可以在UI线程中处理事物,但它会使UI无响应.
  3. 所以我们假设我们有一个与流相关的操作,我们需要下载某种数据.
  4. 我们还允许用户在下载时执行其他操作.
  5. 我们使用异步API来下载文件.不需要工作线程.
  6. 异步操作将其进度报告回UI线程(更新进度条),并且还将其完成报告给UI线程(可以像任何其他事件一样响应它).

这显示了如何只涉及一个线程(UI线程),还有异步操作.您可以启动多个异步操作,但这些操作只涉及一个线程 - 没有线程被阻塞.

async/ await提供了一个非常好的语法,用于启动异步操作然后返回,并在该操作完成时继续该方法的其余部分.

ASP.NET类似,但它没有主/ UI线程.相反,它为每个未完成的请求都有一个"请求上下文".ASP.NET线程来自线程池,当它们处理请求时,它们进入"请求上下文"; 当他们完成后,他们退出他们的"请求上下文"并返回到线程池.

ASP.NET会跟踪每个请求的不完整异步操作,因此当线程返回到线程池时,它会检查该请求是否正在进行任何异步操作; 如果没有,则请求完成.

因此,当您await在ASP.NET中进行不完整的异步操作时,该线程将递增该计数器并返回.ASP.NET知道请求未完成,因为计数器不为零,因此它不会完成响应.线程返回到线程池,此时:没有线程处理该请求.

异步操作完成后,它会将async方法的其余部分调度到请求上下文.ASP.NET抓取其中一个处理程序线程(可能是也可能不是执行该async方法前面部分的相同线程),计数器递减,并且线程执行该async方法.

ASP.NET vNext略有不同; 整个框架中对异步处理程序的支持更多.但一般概念是一样的.

欲获得更多信息:


ive*_*nxu 6

第一次看到异步等待时,我认为它们是异步编程模型的C#语法糖.我错了,异步等待不止于此.它是一个全新的异步模式基于任务的异步模式,http://www.microsoft.com/en-us/download/details.aspx?id = 199199是一篇很好的文章.大多数使用TAP的FCL类都是调用APM方法(BegingXXX()和EndXXX()).以下是TAP和AMP的两个代码段:

TAP样本:

    static void Main(string[] args)
    {
        GetResponse();
        Console.ReadLine();
    }

    private static async Task<WebResponse> GetResponse()
    {
        var webRequest = WebRequest.Create("http://www.google.com");
        Task<WebResponse> response = webRequest.GetResponseAsync();
        Console.WriteLine(new StreamReader(response.Result.GetResponseStream()).ReadToEnd());
        return response.Result;
    }
Run Code Online (Sandbox Code Playgroud)

APM样本:

    static void Main(string[] args)
    {
        var webRequest = WebRequest.Create("http://www.google.com");
        webRequest.BeginGetResponse(EndResponse, webRequest);
        Console.ReadLine();
    }

    static void EndResponse(IAsyncResult result)
    {
        var webRequest = (WebRequest) result.AsyncState;
        var response = webRequest.EndGetResponse(result);
        Console.WriteLine(new StreamReader(response.GetResponseStream()).ReadToEnd());
    }
Run Code Online (Sandbox Code Playgroud)

最后这两个将是相同的,因为GetResponseAsync()调用BeginGetResponse()和EndGetResponse().当我们反映GetResponseAsync()的源代码时,我们将获得如下代码:

task = Task<WebResponse>.Factory.FromAsync(
       new Func<AsyncCallback, object, IAsyncResult>(this.BeginGetResponse), 
       new Func<IAsyncResult, WebResponse>(this.EndGetResponse), null);
Run Code Online (Sandbox Code Playgroud)

对于APM,在BeginXXX()中,有一个回调方法的参数,该方法将在任务(通常是IO繁重操作)完成时调用.创建一个新的线程并异步,它们都将立即在主线程中返回,它们都被解除阻塞.在性能方面,创建新线程会在进程I/O绑定操作(例如读取文件,数据库操作和网络读取)时花费更多资源.创建新线程有两个缺点,

  1. 就像在你提到的文章中一样,内存成本和CLR是
    线程池的限制.
  2. 上下文切换将发生.另一方面,异步不会手动创建任何线程,并且当IO绑定操作返回时它不会有上下文切换.

这是一张有助于理解差异的图片:

在此输入图像描述

此图来自MSDN文章" ASP.NET 2.0中的异步页面 ",它详细解释了旧的异步如何在ASP.NET 2.0中工作.

关于异步编程模型,请从Jeffrey Richter的文章" 实现CLR异步编程模型 "中获取更多细节,在第27章他的书"CLR via Csharp 3rd Edition"中也有更多细节.