C#中async/await的线程ID变化情况
一、简单的起步
Console.WriteLine($"主线程开始ID:{Thread.CurrentThread.ManagedThreadId}");//aawait Task.Delay(100);//cConsole.WriteLine($"主线程结束ID:{Environment.CurrentManagedThreadId}");//b
结果:
主线程开始ID:1
主线程结束ID:4
1、问:async/await会创建新线程吗?
答:async和await并不会直接创建新的线程,而是通过利用异步机制来实现非阻塞的异步操作。
C#中的async和await关键字并不会创建新的线程。它们实际上是用于异步编程的语法糖。
当使用async关键字修饰一个方法时,该方法可以被视为一个异步方法。在异步方法内部,可以使用await关键字来等待其他异步操作的完成。
当遇到await关键字时,异步方法会暂时挂起,让出当前线程的控制权,而不会阻塞线程。当被await的异步操作完成后,异步方法会恢复执行,并返回结果。
在大多数情况下,异步操作并不会创建新的线程,而是通过利用I/O完成端口或其他异步机制来实现异步操作。这样可以避免创建额外的线程,提高程序的性能和资源利用率。
注意,如果使用了Task.Run等方法来包装一个同步的阻塞操作,那么它可能会在新的线程上执行。这样做的目的是为了将阻塞操作转换为异步操作,以避免阻塞主线程。
2、问:异步方法会暂时挂起,是什么意思?
答:在遇到await Task.Delay(100)时,异步方法会暂时挂起,并让出当前线程的控制权。这里的挂起并不是指线程被挂起或阻塞,而是指异步方法暂时停止执行,并将控制权返回给调用它的线程(主线程)。
当遇到await Task.Delay(100)时,它会创建一个延时任务,该任务会在指定的时间(这里是100毫秒)后完成。然后,异步方法会注册一个回调函数,告诉任务完成后要继续执行下一步。
在挂起期间,异步方法不会占用线程资源,而是让线程可以执行其他任务。这样可以提高程序的并发性和资源利用率。
一旦延时任务完成,异步方法会被唤醒,并继续执行后续的代码。这时,并不是创建新的线程来执行延时操作,而是通过异步机制来实现非阻塞的延时操作。
具体来说,当异步方法遇到await Task.Delay(100)时,它会将延时任务交给.NET运行时的任务调度器(Task Scheduler)管理。任务调度器会将延时任务放入等待队列中,并继续执行其他任务。
在指定的时间(100毫秒)后,任务调度器会将延时任务标记为完成,并将其添加到就绪队列中。当调度器调度到该任务时,它会通知异步方法继续执行,并返回到原来的线程(主线程)上。
总之,异步方法的挂起并不是线程的挂起或阻塞,而是暂时停止执行,并让出当前线程的控制权。在挂起期间,线程可以执行其他任务。异步方法通过异步机制来实现非阻塞的延时操作,让出当前线程的控制权,并在延时任务完成后继续执行。
3、问:遇到await时主线程在做啥,玩泥巴吗?
答:是的,它不是阻塞,而是去干其它事去了。
当遇到await关键字时,主线程会暂时挂起(挂起点),这并不会阻塞主线程的执行,而是让出当前线程的控制权,允许主线程去执行其他任务。
同时,await关键字会将异步操作交给任务调度器来管理。任务调度器会根据当前的线程池状态和调度策略,将异步操作分配给适当的线程执行。
当异步操作完成后,任务调度器会通知异步方法继续执行。这时,可能会发生线程切换,执行剩下的代码的线程可能是之前执行异步操作的线程,也可能是其他线程。
这种机制使得异步方法能够以非阻塞的方式执行,并允许主线程在等待异步操作完成时继续执行其他任务,提高了程序的并发性和响应性。
注意,异步方法的挂起和恢复是由任务调度器来管理和控制的,具体的线程调度和切换机制是由.NET运行时来处理的。开发人员并不需要显式地关注线程的创建和管理,而是通过使用async和await来编写简洁、清晰的异步代码。
4、问:await也要开线程吧?
答:不一定,大多数情况下,异步操作并不会创建新的线程,而是利用异步机制(如I/O完成端口)来实现非阻塞的异步操作。
通过使用异步机制,可以将阻塞的I/O操作转换为异步的操作,而不需要创建新的线程。这样可以避免线程的创建和销毁,提高程序的性能和资源利用率。
除了线程池中的线程,调度器也可以使用其他的执行上下文,比如使用事件触发器或计时器来执行异步操作。这种情况下,调度器会将异步操作添加到事件队列或计时器队列中,并在适当的时候触发事件或计时器来执行异步操作。
然而,有些情况下,异步操作可能会创建新的线程。例如:
(1)使用Task.Run等方法:
如果使用Task.Run等方法来包装一个同步的阻塞操作,那么它可能会在新的线程上执行。这样做的目的是为了将阻塞操作转换为异步操作,以避免阻塞主线程。
(2)自定义线程池:
在某些情况下,开发人员可以自定义线程池来控制异步操作的执行。这可能涉及到线程的创建和管理,以满足特定的需求。
注意,创建新的线程可能会增系统资源的开销,并且需要进行线程同步和管理。因此,在设计和实现异步操作时,该根据实际情况和需求来选择合适的方式,以平衡性能、资源利用率和代码复杂性。
总结,大多数情况下,异步操作不会创建新的线程,而是利用异步机制来实现非阻塞的操作。但在某些情况下,可能会涉及到创建新的线程来执行异步操作,以满足特定的需求。
5、问: await完成后,主线程的ID可能不是1了?
答:是的。
当遇到await关键字时,主线程会暂时挂起(挂起点),这并不会阻塞主线程的执行,而是让出当前线程的控制权,允许主线程去执行其他任务。
同时,await关键字会将异步操作交给任务调度器来管理。任务调度器会根据当前的线程池状态和调度策略,将异步操作分配给适当的线程执行。
当异步操作完成后,任务调度器会通知异步方法继续执行。这时,可能会发生线程切换,执行剩下的代码的线程可能是之前执行异步操作的线程,也可能是其他线程。
这种机制使得异步方法能够以非阻塞的方式执行,并允许主线程在等待异步操作完成时继续执行其他任务,提高了程序的并发性和响应性。
具体的来说就是:
当异步操作完成后,任务调度器会通知异步方法继续执行,具体是通过将执行权从之前的线程切换回到原来挂起点的代码,然后继续执行下面的代码。
在异步方法中,遇到await关键字时,会将await之后的代码封装为一个延续(continuation),并注册到异步操作的完成事件上。
当异步操作完成后,任务调度器会将延续添加到就绪队列中,等待调度执行。一旦调度器调度到该延续,它会通知异步方法继续执行,切换回原来的挂起点。
这个通知是通过线程切换和调度机制实现的。具体来说,任务调度器会选择一个可用的线程(可能是之前执行异步操作的线程,也可能是其他线程),并将执行权转移给该线程。这样,异步方法就可以继续执行await之后的代码。
注意,异步方法的继续执行并不是立即发生的,而是在调度器选择并分配线程之后才会发生。具体的线程调度和切换机制是由.NET运行时和任务调度器来处理的,开发人员不需要显式地管理和控制。
总之,异步操作完成后,任务调度器会通过线程切换和调度机制将执行权切换回原来的挂起点,通知异步方法继续执行下面的代码。这样可以实现非阻塞的异步操作和代码的顺序执行。
6、问:那上面的的await应该有答案了吗?
答:是的,上面可以知道在c处挂起,主线程玩泥巴,这个延时交给任务调度器(不一定是创建线程,也可能是事件回调机制),延时完成后回来,任务调度器会选择一个可用线程(可能是主线程,可能是前面异步操作线程,也有可能是新的其它线程,谁闲谁知道呢,服从领导就OK啦),继续执行c处后面的代码。所以d的ID是随机的,谁也说不准。
7、问:什么是上下文?
答:人话就是,上下文(Context)是指执行代码时所处的环境和状态。它包含了一些与执行相关的信息,如线程调度器、同步上下文、同步上下文流动等。
比如,你工作的场所,场景,环境。有电脑,笔,桌子,办公室,等等。
8、问:所有线程都有上下文?
答:在异步编程中,线程执行时都会有上下文。上下文提供了执行环境和状态,包括线程的调度、同步上下文、同步上下文流动等。
人话就是:所有鱼都有自己的生存环境。
9、问:上下文的切换都会有消耗资源?
答:对的。
切换线程上下文可能会涉及一些开销,包括线程的切换、上下文的保存和恢复等。这是因为不同的线程可能具有不同的执行环境和状态,需要进行一些额外的操作来确保正确的执行。
人话就是:如果你原来在A处办公,现在调整到B处去办公,你当然需要搬运、布置,打扫等工作,肯定有些许时间的消耗。
二、再添加一个异步
Console.WriteLine($"主线程开始ID:{Environment.CurrentManagedThreadId}");//aTask task = Task.Run(() =>{Console.WriteLine($"异步线程ID开始:{Environment.CurrentManagedThreadId}");//bThread.Sleep(10);//cConsole.WriteLine($"异步线程ID结束:{Environment.CurrentManagedThreadId}");//d});await Task.Delay(100);//eConsole.WriteLine($"主线程结束ID:{Environment.CurrentManagedThreadId}");//fConsole.ReadKey();
结果:
主线程开始ID:1
异步线程ID开始:3
异步线程ID结束:3
主线程结束ID:4
a处为主线程ID为1,然后新开一个异步线程task,一闪而过去执行e处,又是一个异步线程但有await。所以f是随机的,可能是1,可能是4,但不可能是3,因为此时3被c处占用。
对于b和d,因为c是同步线程,所以b和d都是在同一个线程中执行,它们的ID是相同的为3.
修改一:将C的10毫秒改变为1000毫秒。
Console.WriteLine($"主线程开始ID:{Environment.CurrentManagedThreadId}");//aTask task = Task.Run(() =>{Console.WriteLine($"异步线程ID开始:{Environment.CurrentManagedThreadId}");//bThread.Sleep(1000);//cConsole.WriteLine($"异步线程ID结束:{Environment.CurrentManagedThreadId}");//d});await Task.Delay(100);//eConsole.WriteLine($"主线程结束ID:{Environment.CurrentManagedThreadId}");//fConsole.ReadKey();
结果:
主线程开始ID:1
异步线程ID开始:3
主线程结束ID:4
异步线程ID结束:3
同样b和d仍然同一线程内,肯定相同,所以两者为3。
e处之后,f的ID是随机的,但它不可能是3,此是3仍然在c处占用.
修改二:把e处改为thread.Sleep(1000)
Console.WriteLine($"主线程开始ID:{Environment.CurrentManagedThreadId}");//aTask task = Task.Run(() =>{Console.WriteLine($"异步线程ID开始:{Environment.CurrentManagedThreadId}");//bThread.Sleep(10);//cConsole.WriteLine($"异步线程ID结束:{Environment.CurrentManagedThreadId}");//d});Thread.Sleep(1000);//eConsole.WriteLine($"主线程结束ID:{Environment.CurrentManagedThreadId}");//f
结果:
主线程开始ID:1
异步线程ID开始:3
异步线程ID结束:3
主线程结束ID:1
bcd处一样为3.
e处为同步。由主线程执行ID为1,所以后面的f处也为1.
三、新加异步中的Await
1、两个线程,第一个异步中异步,第二同步:
Console.WriteLine($"主线程开始ID:{Environment.CurrentManagedThreadId}");//aTask task = Task.Run(async () =>{Console.WriteLine($"异步线程ID开始:{Environment.CurrentManagedThreadId}");//bawait Task.Delay(10);//cConsole.WriteLine($"异步线程ID结束:{Environment.CurrentManagedThreadId}");//d});Thread.Sleep(1000);//eConsole.WriteLine($"主线程结束ID:{Environment.CurrentManagedThreadId}");//f
结果:
主线程开始ID:1
异步线程ID开始:3
异步线程ID结束:4
主线程结束ID:1
e处为同步线程,在主线程中,所以到了f时是主线程。
b处由Task.Run申请的线程,ID为3,经过c后,原ID为3的挂起,在延时做完后,恢复执行后面代码时,由调度器选择线程来执行后面的d处,所以d的ID是随机的,但不可能是1.
2、两个线程,第一个异步中异步,第二次await异步。
Console.WriteLine($"主线程开始ID:{Environment.CurrentManagedThreadId}");//aTask task = Task.Run(async () =>{Console.WriteLine($"异步线程ID开始:{Environment.CurrentManagedThreadId}");//bawait Task.Delay(10);//cConsole.WriteLine($"异步线程ID结束:{Environment.CurrentManagedThreadId}");//d});await Task.Delay(1000);//eConsole.WriteLine($"主线程结束ID:{Environment.CurrentManagedThreadId}");//f
结果:
主线程开始ID:1
异步线程ID开始:3
异步线程ID结束:5
主线程结束ID:3
b处为异步线程ID为3,经过C处后,d处随机,显示为5.
e处返回时,b,d使用的线程(3和5)已经返回给线程池,也即线程池是有可能再次给e后面分配1,3,5等,所以这里显示是3.
3、修改上面,把延时调整一下,c处占久点
Console.WriteLine($"主线程开始ID:{Environment.CurrentManagedThreadId}");//aTask task = Task.Run(async () =>{Console.WriteLine($"异步线程ID开始:{Environment.CurrentManagedThreadId}");//bawait Task.Delay(1000);//cConsole.WriteLine($"异步线程ID结束:{Environment.CurrentManagedThreadId}");//d});await Task.Delay(10);//eConsole.WriteLine($"主线程结束ID:{Environment.CurrentManagedThreadId}");//f
结果:
主线程开始ID:1
异步线程ID开始:3
主线程结束ID:5
异步线程ID结束:6
b处分配ID为3,然后c处等待,在d处随机得到分配的ID,由于它是1000毫秒后,即所有任务都执行完成了,只有它,所以它的随机分配是任何可能,可以是3,5,6等。
e处过后,返回时由于b处占用了3(哪怕是挂起),所以在f处调度器随机分配线程不可能ID为3,所以上面分配的是5.
四、Configureawait的失效
Console.WriteLine($"主线程开始ID:[{Environment.CurrentManagedThreadId}]");//aawait Task.Run(async () =>{Console.WriteLine($"异步线程开始ID:[{Environment.CurrentManagedThreadId}]");//bawait Task.Delay(1000);//cConsole.WriteLine($"异步线程结束ID:[{Environment.CurrentManagedThreadId}]");//d}).ConfigureAwait(true);//eConsole.WriteLine($"主线程结束ID:[{Environment.CurrentManagedThreadId}]");//f
结果:
主线程开始ID:[1]
异步线程开始ID:[3]
异步线程结束ID:[4]
主线程结束ID:[4]
上面b处ID结果为3,然后经c处后,在d处随机分配。结果是4.
f处由于前面await的原因,同样也是随机分配,它是最后执行,所以ID有任意的可能(看调度器的分配了)。
这里,说明的是无论Configiure为True还是False,最后都要以await结束,都要返回到主线程的上下文中,所以它“失效了”.
Task.Run会将异步操作放入线程池中执行,而await会在异步操作完成之前阻塞主线程。当异步操作完成后,会尝试切换回主调线程执行await之后的代码。无论e处的参数是true还是false,异步操作完成后,恢复时都会尝试切换回主调线程执行d处或者f处的代码。
问:为什么d与f处的线程大多数是一样的?
答:这个不是绝对的。按优化概率可能是这样。
调度器通常会尽量将执行权切换回刚完成的异步线程,以继续执行原先挂起的代码。这种方式可以减少线程切换和上下文切换的成本,提高执行效率。
当一个异步任务完成后,调度器会考虑以下几个因素来决定是否将执行权切换回刚完成的异步线程:
(1)异步线程的可用性:
如果刚完成的异步线程仍然可用,调度器会优先选择它来执行后续代码,因为这样可以避免线程切换的开销。
(2)异步线程的负载:
如果刚完成的异步线程当前正在执行其他任务,调度器可能会选择一个空闲的线程来执行后续代码,以平衡负载。
(3)上下文切换的成本:
如果切换到刚完成的异步线程的上下文比切换到其他线程的上下文更低廉,调度器可能会优先选择它来执行后续代码。
注意,具体的调度策略和行为取决于调度器的实现和配置。不同的调度器可能有不同的优化策略和行为。因此,在实际应用中,可能会出现一些例外情况,导致执行权并不会立即切换回刚完成的异步线程。
改变一下它的优化,再增加一句await:
Console.WriteLine($"主线程开始ID:[{Environment.CurrentManagedThreadId}]");//aawait Task.Run(async () =>{Console.WriteLine($"异步线程开始ID:[{Environment.CurrentManagedThreadId}]");//bawait Task.Delay(1000);//cConsole.WriteLine($"异步线程结束ID:[{Environment.CurrentManagedThreadId}]");//d}).ConfigureAwait(true);//eawait Task.Delay(1000);Console.WriteLine($"主线程结束ID:[{Environment.CurrentManagedThreadId}]");//f
结果:
主线程开始ID:[1]
异步线程开始ID:[3]
异步线程结束ID:[4]
主线程结束ID:[3]
f处变成了3,看来调试器总是在当前比较优闲的ID(大概猜测就是1,3,4中选秀)。
而且,最难得的是大约有10次运行,终于找到一个难得的截图:
再次证明,优化是有规则的,所以中奖概率高,但并非绝对的。
相关文章:
C#中async/await的线程ID变化情况
一、简单的起步 Console.WriteLine($"主线程开始ID:{Thread.CurrentThread.ManagedThreadId}");//aawait Task.Delay(100);//cConsole.WriteLine($"主线程结束ID:{Environment.CurrentManagedThreadId}");//b 结果: …...
网络安全—黑客技术—自学笔记
目录梗概 一、自学网络安全学习的误区和陷阱 二、学习网络安全的一些前期准备 三、网络安全学习路线 四、学习资料的推荐 想自学网络安全(黑客技术)首先你得了解什么是网络安全!什么是黑客! 网络安全可以基于攻击和防御视角来…...
功夫再高也怕菜刀。多年经验,会独立开发的机器视觉工程师,技术太强,但是找工作能力差劲
功夫再高也怕菜刀,专业的事情交给专业的人去做。 今年7月份中旬的时候,遇到一位老朋友,向我咨询某公司的信息,其实我根本不了解这家公司的情况与实力,向他说了,抱歉,我查下,等我晚上…...
numpy的多项式函数: `poly1d`
Python numpy.poly1d() numpy.poly1d()函数有助于定义一个多项式函数。它使得在多项式上应用 "自然操作 "变得容易。 语法: numpy.poly1d (arr, root, var) 参数 : arr : [array_like] 多项式系数按照幂的递减顺序给出。如果第二个参数(根)被…...
Python灰帽编程——错误异常处理和面向对象
文章目录 1. 错误和异常1.1 基本概念1.1.1 Python 异常 1.2 检测(捕获)异常1.2.1 try except 语句1.2.2 捕获多种异常1.2.3 捕获所有异常 1.3 处理异常1.4 特殊场景1.4.1 with 语句 2. 内网主机存活检测程序2.1 scapy 模块2.1.1 主要功能2.1.2 scapy 安装…...
【20230919】win11无法删除Chrome注册表项
win11无法删除Chrome注册表项 删除以下注册表项发生错误: 计算机\HKEY_LOCAL_MACHINE\SOFTWAR\Google计算机\HKEY_CURRENT_USER\Software\Google 尝试了很多删除注册表方法(例如:编辑remove.reg文件),都不行。 无法…...
TCP/IP客户端和服务器端建立通信过程
客户端和服务器端建立通信过程 使用Qt提供的类进行基于TCP的套接字通信需要用到两个类: QTcpServer:服务器类,用于监听客户端连接以及和客户端建立连接。 QTcpSocket:通信的套接字类,客户端、服务器端都需要使用。服务…...
Python ---使用Fake库向clickhouse造数据小案例
每次insert太麻烦了 先在clickhosue中建表 test_user表 CREATE TABLE dwh.test_user (name String,age Int32,address String,phone String,email String ) ENGINE MergeTree() ORDER BY name; 此时表中暂无数据 用Python脚本来造一些数据 from faker import Faker from c…...
09MyBatisX插件
MyBatisX插件 在真正开发过程中对于一些复杂的SQL和多表联查就需要我们自己去编写代码和SQL语句,这个时候可以使用MyBatisX插件帮助我们简化开发 安装MyBatisX插件: File -> Settings -> Plugins -> 搜索MyBatisx插件搜索安装然后重启IDEA 跳转文件功能 由于一个项…...
使用 Messenger 跨进程通信
什么是Messenger Messenger 也是IPC的方案之一,是基于消息的跨进程通信。基于消息是什么意思?Handler是我们最常用的消息机制,所以 Messenger 对于使用者来说就像是使用 Handler。实际上 Messenger 就是 AIDL 的上层封装而已,它们…...
Spring Cloud Gateway
路由谓词工厂 Route Predicate Factory 1. The After Route Predicate Factory spring:cloud:gateway:routes:- id: after_routeuri: https://example.orgpredicates:- After2017-01-20T17:42:47.789-07:00[America/Denver]# 用日期时间匹配 2. The Before Route Pr…...
JVM 优化技术
文章目录 JVM 优化技术概述方法内联优化说明优点内联条件 栈帧之间数据共享说明优点栈帧之间数据共享条件 JVM 优化技术 概述 JVM常见的优化技术: 方法内联优化。栈帧之间数据共享。 方法内联优化 说明 方法内联(Method Inlining)是JVM…...
【MySQL系列】- MySQL自动备份详解
【MySQL系列】- MySQL自动备份详解 文章目录 【MySQL系列】- MySQL自动备份详解一、需求背景二、Windows mysql自动备份方法2.1 复制date文件夹备份实验备份环境创建bat直接备份脚本 2 .2 mysqldump备份成sql文件创建mysqldump备份脚本 2 .3 利用WinRAR对MySQL数据库进行定时备…...
指针笔试题讲解-----让指针简单易懂(2)
目录 回顾上篇重点 : 一.笔试题 ( 1 ) 二.笔试题 ( 2 ) 科普进制知识点 (1) 二进制 (2) 八进制 (3)十六进制 三.笔试题( 3 ) 四.笔试题( 4 ) 五.笔试题( 5 ) 六.笔试题( …...
使用windbg分析dump文件的方法
https://zhuanlan.zhihu.com/p/613434365 一般操作如下: 准备工作。 打开dump文件。指定符号表文件的路径。指定可执行文件的路径。指定源码文件的路径。在windbg的命令行,输入并执行如下命令 .reload,重新加载前述数据文件。!analyze -v&a…...
【论文阅读 07】Anomaly region detection and localization in metal surface inspection
比较老的一篇论文,金属表面检测中的异常区域检测与定位 总结:提出了一个找模板图的方法,使用SIFT做特征提取,姿态估计看差异有哪些,Hough聚类做描述符筛选,仿射变换可视化匹配图之间的关系…...
SSM - Springboot - MyBatis-Plus 全栈体系(十一)
第二章 SpringFramework 五、Spring AOP 面向切面编程 6. Spring AOP 基于 XML 方式实现(了解) 6.1 准备工作 加入依赖和基于注解的 AOP 时一样。准备代码把测试基于注解功能时的 Java 类复制到新 module 中,去除所有注解。 6.2 配置 Sp…...
深度剖析贪心算法:原理、优势与实战
概述 贪心算法是一种通过每一步的局部最优选择来寻找整体最优解的方法。在每个步骤中,贪心算法选择当前状态下的最佳选项,而不考虑未来可能的影响。尽管它不能保证一定能找到全局最优解,但贪心算法通常简单且高效,适用于许多实际…...
Docker搭建DNS服务器--use
前言 DNS服务器是(Domain Name System或者Domain Name Service)域名系统或者域名服务,域名系统为Internet上的主机分配域名地址和IP地址。 安装 2.1 实验环境 IP 系统版本 角色 192.168.40.121 Ubuntu 22.10 DNS服务器 192.168.40.122 Ubuntu 22.10 测试机器 2.2 …...
“顽固”——C语言用栈实现队列
解题图解: 1、 先用stack1存储push来的数据 2、每当要pop数据时,从stack2中取,如果 stack2为空,就先从stack1中“倒”数据到stack2。 这就是用栈实现队列的基本操作 这道题看起来比较容易,但是!如果你用C语…...
linux内网渗透
一、信息收集 主机发现: nmap -sP 192.168.16.0/24 端口探测 masscan -p 1-65535 192.168.16.168 --rate1000 开放端口如下 nmap端口详细信息获取 nmap -sC -p 8888,3306,888,21,80 -A 192.168.16.168 -oA ddd4-port目录扫描 gobuster dir…...
还没用熟 TypeScript 社区已经开始抛弃了
根据 rich-harris-talks-sveltekit-and-whats-next-for-svelte 这篇文章的报道, Svelte 计划要把代码从 TS 换到 JS 了。 The team is switching the underlying code from TypeScript to JavaScript. That and the update will then allow the team to incorporate…...
2023年9月19日
2> 完成文本编辑器的保存工作 头文件 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QFontDialog> #include <QMainWindow> #include <QFont> #include <QMessageBox> #include <QDebug> #include <QColorDialog> #include &l…...
PowerDesigner 与 mysql 同步数据
PowerDesigner 连接上数据库 创建数据库表 table_5 选择: 点击确认后弹出 点击run执行 刷新数据库表,已创建成功 修改测试表1,新增一个字段 取消全选 选择数据库,勾选修改的表,如果全部勾选的话,就…...
[python 刷题] 271 Encode and Decode Strings
[python 刷题] 271 Encode and Decode Strings 题目: Design an algorithm to encode a list of strings to a string. The encoded string is then sent over the network and is decoded back to the original list of strings. Machine 1 (sender) has the func…...
[QT]day3
1.一个闹钟 widget.cpp: #include "widget.h" #include "ui_widget.h"#include <QWidget> #include <QTimerEvent> //定时器事件处理类 #include <QTime>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {//给播…...
《PostgreSQL事务管理深入解析》
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🐅🐾猫头虎建议程序员必备技术栈一览表📖: 🛠️ 全栈技术 Full Stack: 📚…...
深度分析Oracle中的NULL
【squids.cn】 全网zui低价RDS,免费的迁移工具DBMotion、数据库备份工具DBTwin、SQL开发工具等 关键点 特殊值NULL意味着没有数据,它声明了该值是未知的事实。默认情况下,任何类型的列和变量都可以取这个值,除非它们有一个NOT N…...
Python入门教学——类和对象
目录 一、面向过程和面向对象 1、面向过程 2、面向对象 二、类 三、类对象与类属性 1、类对象 2、类属性 四、类方法与静态方法 1、类方法 2、静态方法 一、面向过程和面向对象 1、面向过程 是一种以过程为中心的编程思想,强调事件的流程和顺序。思想&…...
【数据库系统概论】关系数据库中的关系数据结构
前言关系关系模式关系数据库关系模型的存储结构感谢 💖 前言 上一篇文章【数据库系统概论】数据模型介绍了数据库系统中的数据模型的基本概念。其中提到了关系模型是最重要的一种数据模型。下面将介绍支持关系模型的数据库系统——关系数据库。 按照数据模型的三大…...
remal wordpress/优化营商环境心得体会个人
16.1.3 Docker对网络的支持 Container network interface(CNI) 16.1.4 Docker跨主机通信方案总结 Bridge网络:docker0就是默认的桥接网络 Docker网络驱动: Overlay:是基于VXLAN、NVGRE等封装技术实现overlay叠加网络 Macvlan:基于Docker宿主机物理网卡的不同子接…...
宣威网站建设公司/怎么做一个自己的网站
刘爱贵的个人主页 ----人是要有点理想的 [我的空间] -- 算法收藏 | 我的软件 | 程序人生 | 无题 | 相册 | 留言薄 | SOHU Blog | 关于我 [GNU/LINUX] -- GNU/LINUX | UNIX编程艺术 | UNIX/LINUX哲学思想 | 用GNU/LINUX工作[其他东东] -- 管理十大经典理论 | 羽球飘飘 | 人生哲理…...
wordpress搜索功能加强/直播回放老卡怎么回事
PHP文章摘要生成方法(函数)文章生成摘要的方法有多种,可以用JS在客户端生成,也可以在服务器端生成,当然更不排除在数据库中加一个摘要字段,在发布文章的时候自行设置。以下是在服务器端生成时的方法。我们在写BLOG时经常需要显示文…...
影视传媒公司/外汇seo公司
http://club.pchome.net/thread_1_15_4954062__.html这里贴个网友的防骗秘笈下面给大家以重要提示:一、骗子一般都不支持中介二、在大家使用淘宝链接时一定要慢之又慢,千万别操之过急,注意观察:1、骗子给的淘宝网址一般都比较长&a…...
微网站制作需要多少钱/软文广告
问题描述看完电影后,乐乐回家玩起了积木。 他已经搭好了n堆积木,他想通过调整积木,使得其中有连续W堆积木具有相同的高度,同时他希望高度恰好为H。 乐乐的积木都这了,也就是说不能添加新的积木,只能移动现有…...
微信审批小程序/seo是什么服务
本文为美国俄亥俄州立大学(作者:Christine Ann Bryant)的硕士论文,共97页。 本文研究了在单接收机数据速率有限的情况下,实现多输入单输出(MISO)合成孔径雷达(SAR)空时自…...