dev*_*747 2 c# async-await c#-5.0
我的理解是,如果我使用异步,线程会发出Web请求并继续前进.当响应返回时,另一个线程从那里拾取它.因此,有较少数量的捆绑线程处于空闲状态.这不意味着最大活线程数会下降吗?但在下面的示例中,不使用异步的代码最终使用较少数量的线程.有人可以解释为什么吗?
没有异步的代码(使用较小的线程):
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading;
namespace NoAsync
{
internal class Program
{
private const int totalCalls = 100;
private static void Main(string[] args)
{
for (int i = 1; i <= totalCalls; i++)
{
ThreadPool.QueueUserWorkItem(GoogleSearch, i);
}
Thread.Sleep(100000);
}
private static void GoogleSearch(object searchTerm)
{
Thread.CurrentThread.IsBackground = false;
string url = @"https://www.google.com/search?q=" + searchTerm;
Console.WriteLine("Total number of threads in use={0}", Process.GetCurrentProcess().Threads.Count);
WebRequest wr = WebRequest.Create(url);
var httpWebResponse = (HttpWebResponse) wr.GetResponse();
var reader = new StreamReader(httpWebResponse.GetResponseStream());
string responseFromServer = reader.ReadToEnd();
//Console.WriteLine(responseFromServer); // Display the content.
httpWebResponse.Close();
Console.WriteLine("Total number of threads in use={0}", Process.GetCurrentProcess().Threads.Count);
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用异步的代码(使用更多线程)
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace AsyncAwait
{
internal class Program
{
private const int totalCalls = 100;
private static DateTime start = System.DateTime.Now;
private static void Main(string[] args)
{
var tasks = new List<Task>();
for (int i = 1; i <= totalCalls; i++)
{
var searchTerm = i;
var t = GoogleSearch(searchTerm);
tasks.Add(t);
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("Hit Enter to exit");
Console.ReadLine();
}
private static async Task GoogleSearch(object searchTerm)
{
Thread.CurrentThread.IsBackground = false;
string url = @"https://www.google.com/search?q=" + searchTerm;
Console.WriteLine("Total number of threads in use={0}", Process.GetCurrentProcess().Threads.Count);
using (var client = new HttpClient())
{
using (HttpResponseMessage response = await client.GetAsync(url))
{
HttpContent content = response.Content;
content.Dispose();
Console.WriteLine("Total number of threads in use={0}", Process.GetCurrentProcess().Threads.Count);
Console.WriteLine("TimeSpan consumed {0}", System.DateTime.Now.Subtract(start));
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
}
我明白我的结果包括非托管线程.但是线程总数不应该更低吗?
更新:我使用Noseratio提供的代码更新了异步调用
ThreadPool实际上维护着两个子池,一个用于工作线程,另一个用于IOCP线程.当结果GetAsync可用时,从池中分配随机IOCP线程(I/O完成端口)以处理异步HTTP请求的完成.这就是await执行后的代码.您可以控制每个子池的大小ThreadPool.SetMinThreads/SetMaxThreads,更多关于此内容.
因此,您的非异步代码很难与异步版本进行比较.为了更公平的比较,你应该坚持WebRequest两种情况,例如:
非异步:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace NoAsync
{
internal class Program
{
private const int totalCalls = 100;
private static void Main(string[] args)
{
int maxWorkers, maxIOCPs;
ThreadPool.GetMaxThreads(out maxWorkers, out maxIOCPs);
int minWorkers, minIOCPs;
ThreadPool.GetMinThreads(out minWorkers, out minIOCPs);
Console.WriteLine(new { maxWorkers, maxIOCPs, minWorkers, minIOCPs });
ThreadPool.SetMinThreads(100, 100);
var tasks = new List<Task>();
for (int i = 1; i <= totalCalls; i++)
tasks.Add(Task.Run(() => GoogleSearch(i)));
Task.WaitAll(tasks.ToArray());
}
private static void GoogleSearch(object searchTerm)
{
string url = @"https://www.google.com/search?q=" + searchTerm;
Console.WriteLine("Total number of threads in use={0}", Process.GetCurrentProcess().Threads.Count);
WebRequest wr = WebRequest.Create(url);
var httpWebResponse = (HttpWebResponse)wr.GetResponse();
var reader = new StreamReader(httpWebResponse.GetResponseStream());
string responseFromServer = reader.ReadToEnd();
//Console.WriteLine(responseFromServer); // Display the content.
reader.Close();
httpWebResponse.Close();
Console.WriteLine("Total number of threads in use={0}", Process.GetCurrentProcess().Threads.Count);
}
}
}
Run Code Online (Sandbox Code Playgroud)
异步:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace Async
{
internal class Program
{
private const int totalCalls = 100;
private static void Main(string[] args)
{
int maxWorkers, maxIOCPs;
ThreadPool.GetMaxThreads(out maxWorkers, out maxIOCPs);
int minWorkers, minIOCPs;
ThreadPool.GetMinThreads(out minWorkers, out minIOCPs);
Console.WriteLine(new { maxWorkers, maxIOCPs, minWorkers, minIOCPs });
ThreadPool.SetMinThreads(100, 100);
var tasks = new List<Task>();
for (int i = 1; i <= totalCalls; i++)
tasks.Add(GoogleSearch(i));
Task.WaitAll(tasks.ToArray());
}
private static async Task GoogleSearch(object searchTerm)
{
string url = @"https://www.google.com/search?q=" + searchTerm;
Console.WriteLine("Total number of threads in use={0}", Process.GetCurrentProcess().Threads.Count);
WebRequest wr = WebRequest.Create(url);
var httpWebResponse = (HttpWebResponse) await wr.GetResponseAsync();
var reader = new StreamReader(httpWebResponse.GetResponseStream());
string responseFromServer = await reader.ReadToEndAsync();
//Console.WriteLine(responseFromServer); // Display the content.
reader.Close();
httpWebResponse.Close();
Console.WriteLine("Total number of threads in use={0}", Process.GetCurrentProcess().Threads.Count);
}
}
}
Run Code Online (Sandbox Code Playgroud)
默认情况下,我在系统上看到了以下关于线程池的数字:
{ maxWorkers = 32767, maxIOCPs = 1000, minWorkers = 4, minIOCPs = 4 }
增长线程时线程池是懒惰的.新的线程创建可以延迟最多500ms(有关更多详细信息,请查看Joe Duffy的"CLR线程池注入,口吃问题").
要考虑此行为,请使用ThreadPool.SetMinThreads.有了SetMinThreads(100, 100),我看到同步版本的峰值为~111个线程,而异步版本的峰值为~20个线程(发布版本,没有调试器运行).代表异步版本,这是一个非常具有指示性的差异.
| 归档时间: |
|
| 查看次数: |
406 次 |
| 最近记录: |