C#中关于Task.Yeild()的探究

article/2025/9/6 19:24:42

      在与同事讨论async/await内部实现的时候,突然想到Task.Yeild()这个函数,为什么呢,了解一点C#async/await内部机制的都知道,在await一个异步任务(函数)的时候,它会先判断该Task是否已经完成,如果已经完成,则继续执行下去,不会返回到调用方,原因是尽量避免线程切换,因为await后面部分的代码很可能是另一个不同的线程执行,而Task.Yeild()则可以强制回到调用方,或者说主动让出执行权,给其他Task执行的机会,可以把Task理解为协程,Task.Yeild()和Thread.sleep(0)有点相同。

      为了证明我的结论成立,请看代码:

 1 public static async Task Test1()
 2 {
 3      await Task.CompletedTask;
 4      Thread.Sleep(1000);
 5      Console.WriteLine("Test1任务完成");
 6 }
 7 public static async Task Test2()
 8 {
 9      await Task.Delay(1);
10      Thread.Sleep(1000);
11      Console.WriteLine("Test2任务完成");
12 }
13 public static async Task Test3()
14 {
15      await Task.Yield();
16      Thread.Sleep(1000);
17      Console.WriteLine("Test3任务完成");
18 }
19 static void Main(string[] args)
20 {
21      Console.WriteLine(DateTime.Now);
22      _ = Test1();
23      Console.WriteLine(DateTime.Now);
24      Console.ReadLine();
25 }

 

      按照开头的理论,Test1()异步函数由于await了一个已经完成的任务,所以会继续往下执行,阻塞1秒钟,然后回到调用方,打印的时间之差会相隔一秒。

image_thumb1_thumb

      Test2()异步函数由于await了一个未完成的任务(1ms对于CPU来说是很长的了),所以会返回调用方,然后打印相同的时间,一秒钟之后会打印执行完毕。

image_thumb3_thumb

      Test3()调用了Task.Yeild()函数,主动让出执行权,所以会直接返回调用方,然后打印相同的时间,一秒之后会打印执行完毕。

image_thumb5_thumb

      可以看到,开头的结论是正确的。那么,有什么意义呢?Yeild的意思在这里其实就是退让,让出的意思,让出什么呢?就是让出执行权,这与Thread.sleep(0)让出CPU执行权给其他线程(前提是有其他线程竞争)有机会执行是一个道理。

      请看我的例子:

 1 public static async Task OP1()
 2 {
 3      while (true)
 4      {
 5          await Task.Yield();//这里会捕捉同步上下文,由于是控制台程序,没有同步上下文,所以默认的线程池任务调度器变成同步上下文
 6                                      //也就是说后面的代码将会在线程池上执行,由于线程池工作线程数量设置为1,所以必须主动让出执行权,让其他的
 7                                      //任务有执行的机会
 8          Console.WriteLine("OP1在执行");
 9          Thread.Sleep(1000);//模拟一些需要占用CPU的操作
10      }
11 }
12 public static async Task OP2()
13 {
14      while (true)
15      {
16          await Task.Yield();
17          Console.WriteLine("OP2在执行");
18          Thread.Sleep(1000);
19      }
20 }
21 static async Task Main(string[] args)
22 {
23      ThreadPool.SetMinThreads(1, 1);
24      ThreadPool.SetMaxThreads(1, 1);
25      //Task.Run()方法默认使用线程池任务调度器执行任务,由于主线程不是线程池线程,所以使用Task.Run()
26      var t = Task.Run(async () => 
27      {
28          var t1 = OP1();
29          var t2 = OP2();
30          await Task.WhenAll(t1, t2);
31      });
32      await t;
33      Console.ReadLine();
34 }

 

image_thumb9_thumb

      可以看出OP1()和OP2()两个协程(Task)互相争用一个线程(用户模式下的CPU),如果不主动让出执行权,另一个协程(Task)将不会有机会执行。

      例如:

1 public static async Task OP2()
2 {
3      while (true)
4      {
5          await Task.CompletedTask;//或者是直接去掉
6          Console.WriteLine($"OP2在执行 {DateTime.Now}");
7          Thread.Sleep(1000);
8      }
9 }

 

      这样OP1()将永远不会有机会执行。

image20_thumb_thumb


http://chatgpt.dhexx.cn/article/Msqdmq6U.shtml

相关文章

python yeild next使用注意事项

关于得带的基本使用方法,可以往上查一下。这里主要记录下在编码中可能遇到的报错,和处理方式。 import timedef func3():for i in range(5):yield iwhile True:a next(func3())print(a)time.sleep(1) 如果使用上面这种取值方式,你会发现会…

Java多线程礼让yeild()和插队join()方法案例

一. yeild()和join()方法 1.yeild():线程礼让,让当前正在执行的线程可能暂停,但不阻塞 2.yeild():当前正在执行的线程可能暂停,也可能不暂停。 3.yeild():是静态方法,而join()是非静态方法 4.join():能…

gitlab artifacts too large

gitlab在打包artifacts遇到: Uploading artifacts as “archive” to coordinator… too large archive 413 error 网上看了很多方案,一般都是说在admin账户的setting下找到CI/CD,把Maximum artifacts size (MB)改大点 当然这是其中一个点哈…

IDEA 解决 artifacts not found 问题

目录 1. 问题2. 解答方法一方法二 1. 问题 部署 Tomcat 时,选择 Edit Configuration 无 Artifact 选项。 2. 解答 方法一 选择 Fix 直接修复即可。 方法二 打开 Project Structure;选择 Aritfacts 选项;点击 号,选择 Web …

jenkins使用Send build artifacts over SSH遇到的坑

在jenkins构建项目后,优势需要把jar等文件复制到其他服务器,如下图,可以使用Send build artifacts over SSH功能。 但是在使用时可能会遇到无法复制成功 可以从以下几方面入手,基本可以解决该问题 1、检查是否配好了目标主机的用…

【论文笔记】Details or Artifacts: A Locally Discriminative Learning Approach toRealistic Image Super-Reso

细节还是伪纹理:真实图像超分辨率的局部判别方法 来自于CVPR2022,作者Jie Liang, Hui Zeng and Lei Zhang 论文地址:https://arxiv.org/abs/2203.09195 Abstract: 目前超分想要优异的纹理信息,那GAN(生成…

解析IDEA中的Artifacts配置

1. Artifact 2. Artifact名称 3. Artifact类型 4. 输出路径(也就是Deployment root部署根目录),项目运行后的输出根目录 5. 输出根目录,即4指定的地址 6. 输出目录下的结构层次 针对指定项目,对应分析 1. 输出根…

idea配置Tomcat时没有Artifacts选项

想要解决没有artifacts选项的问题,首先要配置项目结构。 点击加号,选择web 然后修改地址,编译后的文件将会生成在你修改的文件夹下,点击Apply应用所作的修改,然后点击Create Artifacts 此时idea就会在Artifacts下生成一个Web expl…

idea为web项目添加tomcat并配置Artifacts

背景 有一天聪明的小峰从网上找了一个web项目,但是只有代码没有启动步骤,作为小白的我解决这个问题也不太顺利特此记录一下。 主要解决的问题: 为项目添加tomact 配置Artifacts 引入 jar包 小峰找的项目地址:https://github.com/…

idea配置factets和Artifacts

最近需要把项目部署到服务器,需要打个war包,有好多不太明白,把搜索学习到的知识点汇总一下,以备后用,本人使用的版本是2020.3版本。 在说明这个配置过程之前,先简单的介绍一下这两个是什么,有什…

IDEA中WEB项目结构和Artifacts设置

公司的WEB项目结构一直比较随意,没有统一的规范,新增项目也是直接用旧的项目文件夹拷贝过去修改,时间长了以后项目文件结构混乱,研究了半天终于找到了(可能)正确的目录结构设置,能够直接输出正确…

棋盘效应(Checkerboard Artifacts)

定义:棋盘效应是由于反卷积的“不均匀重叠”(Uneven overlap)的结果。使图像中某个部位的颜色比其他部位更深: 具体原因:在反卷积操作时,如果卷积核(Kernel)大小不能被步长&#xff…

Idea 精准到类的打包方式:Artifacts 打包

这种打包方式更精确,可以直接精确到具体类,这种情况下打的包,上传到 Flink web 时,不需要手动写入 class 文件名,它会自动填入,如果没有自动填入,或许是你的 Flink 版本太低了,我的是…

Idea 2022 创建 Artifacts 运行 Tomcat 步骤

每次一个新 web 项目都被 idea 搞的晕头转向。只要是 xml 文件无法发布,初步判断这是 idea 的一个 bug,现整理如下。 首先确保 Project Structure 下 Modules 的配置正确。 Project Structure / Artifacts / 中使用 号菜单进入如下图界面。 从 Modules …

Bug:No artifacts configured

可能是因为项目是直接git下来的,所以项目的框架不完整,缺少web功能,因此在配置tomcat server时,没有artifacts可选 目前已经解决了此问题,因此记录一下解决的方法步骤 配置artifacts 在idea中,依次点击Fi…

Idea的Artifacts

Artifacts(Web部署-2) 项目的打包部署设置,这个是项目配置里面比较关键的地方,重点说一下。 先理解下它的含义,来看看官方定义的artifacts: An artifact is an assembly of your project assets that you…

IDEA通过Artifacts发布Web项目

今天在用IDEA运行一个Java Web项目时突然报错java.lang.ClassNotFoundException: com.mysql.jdbc.Driver,但是我的项目的lib目录下以及添加了jdbc的连接jar包,而且在IDEA中编译没有报错,而且之后我自己添加的两个jar包也找不到,但…

idea Artifacts 配置

以Artifacts方式工作 什么是artifact? artifact是一种用于装载项目资产以便于测试,部署,或者分布式软件的解决方案。例如集中编译class,存档java应用包,web程序作为目录结构,或者web程序存档等。 artifact …

IDEA中的Build Artifacts详解

使用IDEA编写完JAVA代码,需要对外发布时,我们就会用到IDEA的Build Artifacts...功能。在没有创建Artifact时,菜单“Build”|"Build Artifacts..."是灰化的,不可用。所以,第一步是进入project structure创建A…

No artifacts configured

在配置tomcat得时候出现这种情况有可能是,IDEA中没有导入web得框架。 1、点击项目得添加框架这个选项 2、选上,点击ok即可。这是再去看tomcat中就会出现artifacts。