2012-10-01 41 views
6

此前我发布了this有关在客户端或服务中应用Async-Await的问题。在继续讨论这个问题之前,请先阅读这个问题,因为它与问题紧密相关。Async-Await的真正优势?

基于我已经测试了C#4.0(TPL)和C#5.0(异步 - 等待)代码的答案。我使用服务提供的方法的异步和同步版本调用服务,并比较每种情况下使用的线程数。 以下是我使用来测试所使用的资源代码:

主要方法

List<Task<string>> tasksList = new List<Task<string>>(); 
List<int> asyncThreads = new List<int>(); 
List<int> tplThreads = new List<int>(); 
Stopwatch watch = new Stopwatch(); 
watch.Start(); 

// Call the Async version of the method 
for (int i = 0; i < 500; i++) 
{ 
    tasksList.Add(GetNameFromServiceAsync("Input" + i.ToString(), asyncThreads)); 
} 

Task.WaitAll(tasksList.ToArray()); 

watch.Stop(); 

foreach (var item in asyncThreads.Distinct()) 
{ 
    Console.WriteLine(item); 
} 

Console.WriteLine("(C# 5.0)Asynchrony Total Threads = " + asyncThreads.Distinct().Count()); 
Console.WriteLine(watch.ElapsedMilliseconds.ToString()); 

watch.Restart(); 

tasksList.Clear(); 

// Call the normal method 
for (int i = 0; i < 500; i++) 
{ 
    tasksList.Add(GetNameFromService("Input" + i.ToString(), tplThreads)); 
} 

Task.WaitAll(tasksList.ToArray()); 

watch.Stop(); 

foreach (var item in tplThreads.Distinct()) 
{ 
    Console.WriteLine(item); 
} 

Console.WriteLine("(C# 4.0)TPL Total Threads" + tplThreads.Distinct().Count()); 

Console.WriteLine(watch.ElapsedMilliseconds.ToString()); 

异步和同步呼叫与服务现在

static async Task<string> GetNameFromServiceAsync(string name, List<int> threads) 
{ 
    Console.WriteLine(" Start Current Thread : " + System.Threading.Thread.CurrentThread.ManagedThreadId); 
    var task = await client.GetNameAsync(name); 
    threads.Add(System.Threading.Thread.CurrentThread.ManagedThreadId); 
    // Console.WriteLine("End GetNameFromServiceAsync Current Thread : " + System.Threading.Thread.CurrentThread.ManagedThreadId); 
    return task; 
} 

static Task<string> GetNameFromService(string name, List<int> threads) 
{ 

    var task = Task<string>.Factory.StartNew(() => 
     { 
      threads.Add(System.Threading.Thread.CurrentThread.ManagedThreadId); 
     // Console.WriteLine("GetNameFromService Current Thread : " + System.Threading.Thread.CurrentThread.ManagedThreadId); 
      return client.GetName(name); 
     }); 

    return task; 
} 

我已经找出如下结果:

  • 如果我打电话给服务它只使用4-5个线程。
  • TPL调用大约44-45个线程。
  • 异步电话的时间大约为17-18秒
  • TPL电话的时间大约是42-45秒。

我想对我的发现有一些反馈,以便对其他社区成员也有用。这是我早期问题的答案吗?

编辑

问:我的观察结论是,如果我们使用异步等待,而不是TPL的Task.Factory.startNew,那么它会消耗较少的线程。这是正确的吗?如果否,那么这种比较的正确方向是什么?

问:由于我学习异步 - 等待,我想通过某种比较和可靠的代码来证明它的价值。

+8

你的问题到底是什么? –

+0

通过使用异步 - 等待我们可以获得内存优势(将使用较少的资源)。这是我从我以前的问题得到的,或者我理解的,我想知道的是这是它的答案。我想通过使用异步等待在可伸缩性优势的背景下提出要求。是否与我所得出的结论一致? –

+0

一个重要的优点是明确的,即用户在做同步代码时不能说他们面临异步问题。 –

回答

12

客户端async(与同步代码相比)通常会提高内存的成本成本的响应性。

服务器端async(与同步代码相比)通常通过减少内存/线程使用率来提高可伸缩性。这些优点也适用于客户端async(与多线程代码相比)。

这两个都是极端的概括,肯定有他们错了的情况。

更新:

我的观察结论是,如果我们使用异步等待......,那么它会消耗较少的线程。

async/await启用可维护的异步代码。就他们自己而言,他们与创建线程没有任何关系。但是,它们通常与Task.Run(或Task.Factory.StartNew)一起使用来创建后台任务。

由于我学习异步 - 等待,我想通过某种比较和可靠的代码来证明它的价值。

asyncawait是编译器转换。它们使编写异步程序变得更容易 - 就是这样。

如果您将它们与同步代码进行比较,那么您通常会看到改进的响应性和/或可伸缩性。如果您将它们与现有的异步代码进行比较,那么它们通常会在代码可维护性方面效率较低,但会超过该值。

+0

谢谢斯蒂芬。我已经更新了我的问题。 –

+0

已更新的答案。 –