Task.Yield将任务重新安排到线程池队列,并且可以执行等待线程的其他任务。当代码行第一次出现await Task.Yield();后,会重新排队到线程池,获取线程来执行后续的代码(此时不排除获取到当前调用的主线程,有可能获取到新的线程,如果获取到的是调用主线程仍然是以异步方式执行的,CPU时间片),且不会阻塞调用主线程,得到的效果就是主线程和异步线程是并行执行的,互不干扰。使用Task.Yield之后是为了优化线程调度,让最需要主线程处理的地方去处理,将主线程时间让给其他最需要的地方,然后在线程池排队重新获取处理线程。除了最极端的情况之外,线程的调度程序能够通过更改每个线程的执行来解决问题,允许每个短片时间运行,而不是运行每个操作完成。 最重要的是,通过使用线程池可以更有效地解决问题,线程池可以具有与可选项一样多的工作者,并以优化吞吐量的方式排队实际工作。
使用 async 和 await 对客户端应用带来的最大好处在于提高了响应能力。事实上,相比服务器将线程专用于接收到的每个请求,使用 async 和 await 能够使服务器多处理一个数量级的请求。
考虑使用两个服务器:一个运行异步代码,一个不运行异步代码。 鉴于本示例的目的,每个服务器只有 5 个可用于服务请求的线程。 请注意,这样小的数目仅可用于演示。
假设两个服务器都接收到 6 个并发请求。 每个请求执行一个 I/O 操作。 未运行异步代码的服务器必须对第 6 个请求排队,直到 5 个线程中的一个完成了绑定 I/O 的工作并编写了响应。 此时收到了第 20 个请求,由于队列过长,服务器可能会开始变慢。
运行有异步代码的服务器也需对第 6 个请求排队,但由于使用了 async 和 await,绑定了 I/O 的工作开始时,每个线程都会得到释放,无需等到工作结束。 收到第 20 个请求时,传入请求队列将变得很小(如果其中还有请求的话),且服务器不会变慢。
使用 async 和 await处理时,当主线程遇到await时会解除对调用主线程的占用,从新获取线程处理运行后面的代码,计算结果会在调用主线程上排队等待处理,最后主线程将返回执行得到结果
static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int threadId2 = Thread.GetCurrentProcessorId();
Console.WriteLine("外部:線程id=" + threadId2);
bool guo = false;
//調用異步
var gg = GetIntMsAsync();
//var gg = GetIntMsAsync().ConfigureAwait(false);
bool isFirst = false;
AGAIN:
if (isFirst)
{
stopwatch.Restart();
//同步
GetIntMs();
guo = true;
}
isFirst = true;
Console.WriteLine("GetIntMsAsync下面的代碼...");
for (int i = 0; i < 10; i++)
{
//Console.WriteLine("mian裡面的方法" + i);
WebClient webClient = new WebClient();
string content = webClient.DownloadString("https://www.qq.com");
Console.WriteLine($"{i + 1} mian下載的內容:" + content.Length);
}
stopwatch.Stop();
long haoshi= stopwatch.ElapsedMilliseconds;
Console.WriteLine("Hello World!執行耗時"+ haoshi);
if (!guo)
{
goto AGAIN;
}
Console.ReadKey();
}
static int GetIntMs()
{
int threadId = Thread.GetCurrentProcessorId();
Console.WriteLine("\r\n同步執行開始:線程01 id=" + threadId);
int km = 0;
km = 8759 * 156;
if (km > 1800)
{
km = 85200;
}
int i = 0;
for (; i < 10; i++)
{
WebClient webClient = new WebClient();
string content = webClient.DownloadString("https://www.baidu.com");
Console.WriteLine($"{i + 1}下載的內容大小:" + content.Length);
}
return i;
}
static async Task<int> GetIntMsAsync()
{
int threadId = Thread.GetCurrentProcessorId();
Console.WriteLine("Task:線程01 id=" + threadId);
await Task.Yield();
int threadId5 = Thread.GetCurrentProcessorId();
Console.WriteLine("Yield Task后:線程02 id=" + threadId5);
int i = 0;
for (; i < 10; i++)
{
WebClient webClient = new WebClient();
string content = webClient.DownloadString("https://www.baidu.com");
Console.WriteLine($"{i + 1}下載的內容大小:" + content.Length);
}
return i;
}