最新要闻
- 你同意?张朝阳:《流浪地球2》跟好莱坞还是没法比
- 【天天时快讯】奇葩!哈尔滨机场一旅客为逃避安检把活蜗牛藏嘴里
- 环球热议:Google放大招对抗ChatGPT:结果低级答错题 市值蒸发1000亿
- 微头条丨单枪匹马也能拍大片!这次又让大疆给拿捏了
- 快资讯:史上最强AMD显卡!撼迅正式发布水冷RX 7900 XTX 还是单插槽
- 每日观点:法国调香师夸国产花露水清新还美丽 要卖450元 网友:六神YYDS
- 《蚁人3》女儿凯茜中文预告公布 首映礼美艳图赏
- 当前关注:重回中国!福建13岁女孩4.82秒打破鲁班锁世界纪录
- 今日讯!ROG新款幻14笔记本即将上市:锐龙9 7940HS 可选RTX 4060
- 免费用!中国信通院全球网测APP iOS版上线:支持5G/千兆接入测速
- 速读:71款任选 森马T恤33元清仓手慢无
- 动态:祝福!比尔盖茨有新女友了 身家超33亿女富婆:双方沉默 前妻也有新恋情
- 完美收官!《三体》电视剧最后5集被赞爆:老外满分刷屏
- 快看:80km续航 雅迪电动车DN2千元秒杀:2699元起还是新国标
- 今亮点!女子熬夜看《狂飙》:患高启强同款干眼症
- 世界热头条丨逆天 韩国学生用ChatGPT写论文“喜”提0分 校方:剽窃!
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
今日热闻!基于高层次综合器(Vivado HLS)的硬件优化[原创www.cnblogs.com/helesheng]
最近在写一本Xilinx的FPGA方面的书,现将HLS部分内容在这里分享给大家,希望大家喜欢,也欢迎批评指正。以下原创内容欢迎网友转载,但请注明出处:https://www.cnblogs.com/helesheng
通过前面的学习,相信读者已经基本掌握了高层次综合器的基本使用方法,本小节将学习使用高层次综合器提供的工具,优化上一小节实现的FIR滤波器消耗的FPGA资源和执行时间。
仔细阅读代码8.4,可以发现它每次只接收一个数据x(点),输出一个数据(存储在y所指向的存储器中)。作为一个有限冲击响应滤波器(FIR),它的输出只由当前输入和以前的输入计算产生,这段代码将之前的输入数据都缓冲在shift_reg数组之中。函数中的for循环两个具体操作:其一,滤波器系数和输入历史数据之间的乘加运算。其二,对存储在shift_reg数组中历史数据进行移位,以将新的输入存储数组,并对老的历史数据进行进一步老化。
(资料图)
可以看出上述代码实现的FIR滤波器和用传统高级语言经由CPU或DSP逐句实现的方法没有多大区别,所有的计算仍然采用“串行”方式执行,并且需要在电路中增加大量流程控制逻辑。既没有发挥可编程逻辑器件“并行”化执行算法的优势,有没有节约多少硬件资源,可以通过多种手段优化上述高层次综合器代码。
1、优化条件判断语句
代码8.4中for循环内部的if条件判断语句将被高层次综合器综合后的硬件电路的工作效率十分低效,因为判断后两个分支中的乘加和移位操作都只有在if判断执行后才能真正执行,从而限制了后续优化中这些运算“并行化”的实现。是我们在优化中首先要解决的问题。另外,优化掉判断语句还能省去综合结果硬件电路中的条件判断电路,从而降低电路的整体复杂度,可谓一举多得。
仔细观察代码后可以发发现,去掉if条件判断并不困难。因为该判断中的一个分支只发生在i == 0时,i等于其他值的情况都只会执行另外一个分支;另外,所有的分支在每次循环中都必将被依次执行。因此,可以将i为0时对应的分支直接放到for循环的外部,最后执行即可,不会影响执行结果。得到优化代码如下(注意,代码中的Shift_Accum_Loop标签和C语言中语句的标签语法要素和作用完全相同,用于表示某些语句,不会产生任何实质性代码或硬件)。
1 #define N 11 2 typedef int coef_t; 3 typedef int data_t; 4 typedef int acc_t; 5 void fir(data_t *y,data_t x) 6 { 7 coef_t C[N] = {53,0,-91,0,313,500,313,0,-91,0,53}; 8 static 9 data_t shift_reg[N];10 acc_t acc;11 int i;12 acc = 0;13 Shift_Accum_Loop:14 for(i = N-1;i > 0;i--){15 shift_reg[i] = shift_reg[i-1];16 acc += shift_reg[i] * C[i];17 }18 acc += x * C[0];19 shift_reg[0] = x;20 * y = acc;21 }代码8.6
下图是代码8.6经高层次综合器综合后的结果,可以看到代码的设计延时明显降低,而乘加运算所使用的DSP48资源增加,显然计算的并行度增加了。
图8.3.1 优化后的综合报告1
2、for循环拆分
如前所述,代码8.6中的for循环中有两种操作:乘加(标签为MAC)和移位(标签为TDL),将它们分别放在两个for循环中,有利于高层次综合器针对每个循环进行硬件优化,提高整体的代码效率。拆分后的代码如代码8.7所示。
1 #define N 11 2 typedef int coef_t; 3 typedef int data_t; 4 typedef int acc_t; 5 void fir(data_t *y,data_t x) 6 { 7 coef_t C[N] = {53,0,-91,0,313,500,313,0,-91,0,53}; 8 data_t shift_reg[N]; 9 acc_t acc;10 int i;11 TDL:12 for(i = N - 1;i > 0;i--){13 shift_reg[i] = shift_reg[i - 1];14 }15 shift_reg[0] = x;16 acc = 0;17 MAC:18 for(i = N-1;i >= 0;i--) {19 acc += shift_reg[i] * C[i];20 }21 * y = acc;22 }代码8.7
读者综合代码8.7后会惊异地发现他的设计延迟相比代码8.6不减反增!其实,这是很正常的现象,我们拆分for循环的目的是为了针对乘加和移位分别进行优化,而现在还未进行任何具体优化操作,拆分循环只会增加循环控制电路的复杂程度,性能自然降低了。我们需要进一步分别优化MAC和TDL两个循环。
3、移位循环的展开
如果不做专门的制定,高层次综合器将把硬件电路配置为顺序执行for循环结构。但对于循环的第i次计算不需要上一次(i-1次)循环计算的执行结果的“非依赖”循环,如果在硬件电路中增加对该for循环的并行性支持,可以进一步充分发挥可编程逻辑器件的并行结构优势,提升算法实现的效率。在代码8.7中实现历史数据存储移位的TDL循环就属于这类可以通过“循环展开”提升算法电路并行性的循环。
代码8.8将TDL循环展开为2次移位为一组的新循环体,即每次循环中循环体执行两个历史数据移位操作,这需要综合后得到的电路具有能够同时执行两个移位操作的硬件,但循环次数将降低为原来的一半。
1 TDL:2 for(i = N - 1;i > 1;i = i - 2){3 shift_reg[i] = shift_reg[i - 1];4 shift_reg[i - 1] = shift_reg[i - 2];5 }6 if(i == 1){7 shift_reg[1] = shift_reg[0];8 }9 shift_reg[0] = x;代码8.8
代码8.8由于每次对两个数据进行了移位,TDL循环中对索引i的操作变为每次减2(i == i - 2)。代码8.8还在循环后面增加了一个if条件判断,以防止循环次数为奇数时最后一次移位未被执行,当然如果事先知道N的值是奇数还是偶数,也可以避免使用这条判断语句。
上述展开操作,除了使用代码8.8所示的“手工”代码方式展开,还可以通过高层次综合器支持的指令方式“自动”完成。在Vivado HLS开发工具中,添加指令的方式有两种:
其一,直接在C语言源文件中嵌入编译脚本指令,具体位置在需要配置的循环体for语句之后。指令格式为:#pragma HLS unroll factor=2,以代表要求综合器将循环并行化为每次执行两个移位操作。(注意,这种嵌入源码的编译指令都以#开始)
1 TDL:2 for(i = N - 1;i > 0;i--){3 #pragma HLS UNROLL factor=24 shift_reg[i] = shift_reg[i - 1];5 }6 shift_reg[0] = x;代码8.9
其二,通过图形界面编辑脚本指令,并将所有编译指令集中存放在专门的指令文件(Directive File)或循环所在的高级语言源文件中。这种方式需要在Vivado HLS界面右侧的指令区(Directive)中找到需要添加编译指令的循环,右击该循环体进行配置(只有在打开C源文件的情况下,才能在右侧的指令区找到需要编辑的循环)。指令编辑界面如下图8.3.2所示。
图8.3.2 高层次综合器指令编辑界面
在专门的指令文件添加过编译指令的循环将会在Vivado HLS开发环境右侧的指令区中看到以%开头的编译指令。如下图8.3.3所示。
图8.3.3 添加了编译指令的指令区
显然,上述两种方式添加编译指令的展开方式具有阅读、修改方便,不易出错的优势,要远优于“手工”代码展开方式。若比较代码8.9所示的源码添加指令的方式和图8.2.14所示的在专门的指令文件中添加指令的方式哪种更好,则要根据开发者的需求来决定:源码和指令的分离有利于在更高层面上对工程整体进行优化,而直接在源码中写入指令则有利于针对具体代码的灵活优化。为方便叙述,本书后续都采用直接在源码中写入指令的方式进行编译配置和优化,但显然所有指令也可以通过图形界面完成配置。
最后,关于移位循环的展开还可针对移位寄存器本身的实现方式进行配置优化:若将移位寄存器shift_reg[N]配置在BRAM中,则由于BRAM只有两个读端口和一个写端口,则在单个时钟周期中最多完成一个写和两次读,代码8.8和8.9所希望的两次移位操作就只能在两个周期中才能完成。将所有的shift_reg[N]放在独立的寄存器中可以实现在单个时钟周期中完成多个移位寄存器单元读写的要求,使用编译指令#progmaHLS array_parition variable=shift_reg complete能够实现该功能。
4、乘加循环的展开
代码8.7中的乘加循环(标签为MAC的循环)中的每次乘加操作需要读取移位寄存器shift_reg[N]和系数寄存器C[N]中的值,并对它们相乘后累加到和acc中。如果要将这个乘加循环并行化,最大的障碍在于acc中的值存在“依赖关系”——即只有执行完上一次循环的加法得到acc的值后,才能执行下一次循环的加法。增加乘加循环并行度的关键是解除(或部分解除)这种依赖关系。
熟悉数字电路的读者应该知道,可编程逻辑器件可以实现加数多于二个的多加数的加法器,例如我们使用可以对五个加数求和的加法器,就可以解除四次乘加运算之间的结果“依赖关系”,从而增加综合结果电路的并行度。代码8.10就是利用多加数加法器增加解决依赖关系的实例。
1 MAC: 2 for(i = N - 1;i >= 3;i -= 4){ 3 acc += shift_reg[i] * C[i] + 4 shift_reg[i - 1] * C[i - 1] + 5 shift_reg[i - 2] * C[i - 2] + 6 shift_reg[i - 2] * C[i - 2] + 7 shift_reg[i - 3] * C[i - 3]; 8 } 9 for(;i >= 0; i--){10 acc += shift_reg[i] * C[i];11 }代码8.10
其中,第一个for循环将五次加法合在了一个语句中实现,解除了这四次乘加结果求和对上一个乘加结果的依赖,使得这四个乘加可以并行执行(乘法操作可由不同的硬件,如DSP48E模块,同时分别完成)。当然,和前面的移位循环TDL一样,运算次数不一定能够整除并行因子4,需要后面一个for循环来完成最后的工作。如果实现指导循环次数为4的整数倍,后面的for循环也完全可以省去。
当然,代码8.10是为了方便的说明解决乘加循环依赖关系的办法给出的代码,实际工程中,工程人员一般通过Vivado HLS开发工具提供的添加指令功能在源码(在指令区中以#标志)或专门的指令文件(在指令区中以%标志)中添加编译指令的方式,自动添加心慌并行展开指令。完成代码8.10功能的编译指令为:#pragma HLS UNROLL factor=4。还可以通过在该指令中增加优化参数skip_exit_check来禁止高层次综合器检测并行化后循环是否完成(即代码8.10中的第二个循环),从而提高代码的效能。但这样做的前提是实现知道循环次数刚好能被展开因子整除。
若在编译指令中不给出展开因子factor,高层次综合器将把循环全部展开,不再通过多个时钟依次执行循环体,而是将每次循环都使用独立的硬件电路展开执行。这样将获得最快的执行时间,也将消耗非常多的硬件。代码8.11就是将乘加循环完全展开的代码,同图8.3.4是代码8.11的综合报告,可以看到设计延迟和吞吐量显著降低,但消耗的硬件资源也大大增加了。
1 AC:2 for(i = N-1;i >= 0;i--) {3 #pragma HLS UNROLL4 acc += shift_reg[i] * C[i];5 }代码8.11
图8.3.4 优化后的综合报告2
需要注意的是,由于目标器件的资源是有限的,并非所有的展开都能实现,读者需要根据项目目标器件和项目性能需求综合取舍设计展开的而程度。
5、数据位宽优化
C语言本身定义了众多的数据类型,如定点的char、short、int、long等,浮点的float、double等。但由于C语言最初是为图灵计算机设计的,现代通用计算机处理数据的宽度多为8、16、32、64位等2的整数次幂,导致这些数据类型所对应的硬件也分别为8、16、32、64位。对可编程逻辑器件而言,并没有类似计算机这样对位宽的限制。因此高层次综合器的使用者可以根据算法的实际需要,定义任意宽度/精度的定点数据。
值得注意的是,高层次综合器针对C和C++使用不同的库和类型名称来实现任意精度的定点数。C语言使用的头文件名称为ap_cint.h(即需要在使用任意精度定点数的C源文件中包含#include “ap_cint.h”语句),使用的数据类型名称为intN或uintN,例如代码8.12所示。
1 int7 Var1;2 uint58 Var2;3 ……代码8.12
C++使用的头文件名称为ap_int.h(即需要在使用任意精度定点数的CPP源文件中包含#include “ap_int.h”语句),使用的数据类型名称为ap_int
1 ap_int<7> Var1;2 ap_uint<58> Var2;3 ……代码8.13
浮点数方面,高层次综合器通过调用技术库的方式提供浮点运算功能,因此所使用的浮点数的格式必须符合IEEE754规定的浮点格式,而不能任意改变float和double类型指数部分和小数部分所占用的硬件宽度,否则将无法满足技术库中IP对数据格式的要求。
至于定点变量数据位宽的确定,可以遵循以下几个简单原则:
1)加法/减法的原则是,两个位宽同为n位的变量进行加法/减法后,结果占用的位宽为N+1位。
2)乘法的原则是,两个位宽同为n位的变量进行乘法后,结果占用的位宽为2×n位。
3)除法的原则是,一个位宽为n位的变量除以一个位宽为m位的变量后,若不考虑小数部分的话,结果占用的位宽为(n-m)位;若需要考虑使用定点小数表达结果,则可以根据除法结果需要的精度来确定结果占用的位宽。
以代码8.3和代码8.4为例,若输入x为12位补码输出ADC(数模转换器)的转换结果,则x可以定义为int12数据类型,存储历史数据的shift_reg[N]也可以定义为int12类型。系数数组C[N]的最大值和最小值分别为500和-91,可以定义为int9数据类型。acc需要存储N=11个12位数据与9位系数乘积(12+9=23位)结果,最多为23+4=27位(不小于log(11,2)的最小整数为4)。若需要保留acc的所有计算精度,可见acc定义为int27类型。
6、流水线优化
正如本章第一小节最后介绍的,如图8.1.11所示,对高层次综合器输出结果的硬件电路优化的另一种有效方式,是通过“流水线”的方法提高硬件电路的并行性,从而提升电路处理数据的平均吞吐量性能。
但在默认情况下,高层次综合器不会开启流水线优化,只是顺序完成高级语言给出的流程或循环任务。实际上在大多数情况下,在分解算法所需的硬件操作后可以发现某些“微步骤”之间不存在数据依赖关系,可以通过流水线方式并行化这些微步骤。例如FIR滤波器例子中的每个乘加操作可以分解为读取移位寄存器和系数数值,执行乘法操作和执行加法操作三个微步骤。对第一组两个乘数的乘法操作与对第二组两个乘数的读操作之间不存在数据依赖关系,硬件电路完全可以在执行第一组数乘法的同时,读取第二组数,从而大大节约算法的整体执行时间。同样道理,执行加法操作的同时也可以执行后续数据的读取和乘法操作。因此在最佳状态下,可以实现图8.3.4所示的乘加运算流水线,流水线中同时被处理的有三笔数据。
图8.3.4乘加操作流水线示意图
高层次综合器支持通过编译指令实现对流水线的配置,在Vivado HLS环境右侧的指令窗口中对代码8.7中的MAC循环右击添加指令,其指令格式为:#pragma HLS PIPELINE II=2。其中PIPELINE代表这是一条流水线配置指令,字符串“II=2”中的数字代表循环起始间隔,也就是图8.3.4两次乘加执行的延迟时间。当然这个延迟时间数值不一定能够实现,开始阶段可以从大到小使用不同的数值进行尝试,直到获得最佳时间和资源效率。当然,由于本FIR滤波器中乘加操作的次数为11,尝试使用大于或等于11的数值是没有意义的。如果对循环起始时间间隔没有明确的要求只要获得最佳性能,则可以在指令中省略这部分,将指令改写为#pragma HLS PIPELINE,高层次综合器会尝试帮助你找出最佳的数值。
代码8.7中的TDL循环的循环体是进行移位操作,移位操作也可以分解为读取数据和移位写入两个微步骤,对TDL循环使用流水线优化指令也能获得提升执行时间的效果。
图8.3.5所示的是对代码8.6中的MAC和TDL两个循环都使用了流水线优化后的综合报告,对比图8.3.1得到的未做流水线优化后的综合报告,可发现目标硬件的性能得到了很大提升。
图8.3.5 优化后的综合报告3
需要特别指出的是,循环展开和流水线优化对电路处理算法的优化作用不一定能够叠加。原因是当循环被充分展开后,对每一笔数据的处理都有专门的硬件电路负责并行处理,这时再试图通过流水线优化提高并行度的效果就不明显了。对比展开和流水线优化两种方式可以发现:展开是纯粹的以硬件资源换处理时间——靠投入更多资源提升处理能力;流水线优化是通过调度现有资源工作时序,提升每个资源的工作效率实现的,需要增加的资源投入比较有限。
高层次综合器是Xilinx可编程逻辑器件开发中更新最活跃的工具之一,自问世以来获得了大量的关注,功能也发生了很大的改变。本章的介绍具有基础性和引导性,试图在较短的篇幅内帮助读者建立高层次综合器的基本概念,为未来的进一步使用铺平道路。但本章写作中难免出现挂一漏万和内容更新不及时的问题,建议需要深入该工具的读者关注Xilinx官方网站不断更新的应用笔记。
今日热闻!基于高层次综合器(Vivado HLS)的硬件优化[原创www.cnblogs.com/helesheng]
你同意?张朝阳:《流浪地球2》跟好莱坞还是没法比
【天天时快讯】奇葩!哈尔滨机场一旅客为逃避安检把活蜗牛藏嘴里
环球热议:Google放大招对抗ChatGPT:结果低级答错题 市值蒸发1000亿
微头条丨单枪匹马也能拍大片!这次又让大疆给拿捏了
快资讯:史上最强AMD显卡!撼迅正式发布水冷RX 7900 XTX 还是单插槽
Spring配置类理解(Lite模式和Full模式)
环球速讯:JAVA中如何判断一个ResultSet结果集是否为空
【天天速看料】MYSQL脱敏 || 给开发人员限制权限,保证mysql数据库数据安全
重点聚焦!小白也能做应用(二)之fusion app增加B站视频页面
每日观点:法国调香师夸国产花露水清新还美丽 要卖450元 网友:六神YYDS
MATLAB 实现点云累计-坐标系转换-目标范围点云提取(附代码与代码注释)
【全球快播报】面向对象知识点汇总(小白必会)
(一)浅谈人工智能:ChatGPT
《蚁人3》女儿凯茜中文预告公布 首映礼美艳图赏
环球热消息:【一句话】@Configuration和@Component的区别
世界看热讯:《分布式技术原理与算法解析》学习笔记Day06
焦点消息!ASP.NET Core+Element+SQL Server开发校园图书管理系统(完)
全球看点:if else 代码优化实战
全球动态:网络协议-ssh基础
当前关注:重回中国!福建13岁女孩4.82秒打破鲁班锁世界纪录
今日讯!ROG新款幻14笔记本即将上市:锐龙9 7940HS 可选RTX 4060
免费用!中国信通院全球网测APP iOS版上线:支持5G/千兆接入测速
速读:71款任选 森马T恤33元清仓手慢无
动态:祝福!比尔盖茨有新女友了 身家超33亿女富婆:双方沉默 前妻也有新恋情
完美收官!《三体》电视剧最后5集被赞爆:老外满分刷屏
快看:80km续航 雅迪电动车DN2千元秒杀:2699元起还是新国标
Copula
今亮点!女子熬夜看《狂飙》:患高启强同款干眼症
世界热头条丨逆天 韩国学生用ChatGPT写论文“喜”提0分 校方:剽窃!
快资讯:再续一个月:《阿凡达:水之道》再次宣布延长上映
28款CPU性能实测:Intel实力屠榜 AMD游戏神U赢回面子
全球消息!全国首座高速公路重卡充换电站亮相:电池包350kWh 3分钟自动换电
基于图的下一代入侵检测系统
环球快资讯丨MySQL——性能优化的关注点
天天简讯:记录--Cesium+Vue实战教程——地图导航
世界关注:人工智能(Python)教程_编程入门自学教程_菜鸟教程-免费教程分享
天天要闻:安卓常用shell命令大全
环球视点!无损压缩鼻祖去世了 没有他就没有今天的Zip、PNG、PDF
当前观点:博主“科普”鲸鱼会假装搁浅吸引人来救 博物杂志辟谣:九死一生
天天快讯:行驶中会“熄火” 大众召回超2万辆ID.4电动车
世界报道:欧洲玩家吐槽《霍格沃茨之遗》捏脸系统:最浅的皮肤选项依然很深
当前速看:Stochastic Methods in Finance (1)
【独家】.Net6对AOP的多种支持之IAsyncResourceFilter
世界观天下!常见的python技术难点分享
当前速讯:Nodejs原型链污染
世界要闻:[threeJS]--- 外部导入的模型如何编程式实现帧动画以及调用模型自带的动画
情人节必备:德芙香浓黑巧12元/碗大促
逃离银河系!科学家在仙女星系中发现银河移民
世界快播:山东女子中淘宝彩票锦鲤:直播1小时刮594张彩票 中7170元
天天滚动:骁龙8+满血版、残血版差价非常大 一加揭秘:能差1个亿
防止技术垄断:昆仑万维宣布将在年内开源类ChatGPT代码
【全球播资讯】陕西旅游集团旗下景区春节期间累计接待超 200 万人次,这背后也有火山引擎 VeDI 的身影
当前热门:分享5个我不能没有的Vue.js库,不信你用不上
KingbaseES libstdc++.so.6 version 'CXXABI_1.3.8'问题处理
敏捷数据科学教程_编程入门自学教程_菜鸟教程-免费教程分享
MPI库并行Fortran程序:进程通讯
微头条丨女子带汉堡进星巴克被拦 称味道大会影响其他顾客 网友抵制
微信数据再多都够用 真我GT Neo5 1TB干到3499元:旗舰射门员
新资讯:14岁女孩连续玩手机81小时险猝死 专家提醒:家长一定要控制
【环球时快讯】1TB手机不到3500元!网友评价真我GT Neo5:这让友商很难做
世界新消息丨又多了一种摸鱼手段 小红书网页版上线:左图右文 沉浸大屏
快看:Android教程_编程入门自学教程_菜鸟教程-免费教程分享
天天日报丨vue2和vue3的区别有哪些?
docker学习
【全球热闻】剑指Offer 05. 替换空格(java解题)
信息:首个教育圈ChatGPT来了!网易有道将推生成式AI:可批改作文
每日快播:创下历史第二!《霍格沃茨之遗》steam在线人数达48万
快看点丨哭笑不得!西班牙火车尺寸太大无法过隧道:白花2亿多欧元
成都现飞鸟撞树现象 网友疑灾害前兆!专家回应:想多了
环球今日报丨用ChatGPT做表格真香!只需动嘴提要求和复制粘贴
Java基础三元运算符
世界快消息!Crystal Reports 教程_编程入门自学教程_菜鸟教程-免费教程分享
新资讯:再有人问你分布式事务,把这篇文章砸过去给他
有了 ETL 数据神器 dbt,表数据秒变 NebulaGraph 中的图数据
天天播报:部分玩家批评《塞尔达传说:王国之泪》新宣传片:太中庸没新意
环球热讯:比亚迪百万新车或搭载:余承东李想力挺增程式到底落不落后?专家一句真相
C# 学习async/await(个人理解)
30 个 IDEA 常用小技巧,应有尽有,让你的撸码效率直接起飞...
【天天聚看点】世界有史以来最大百科全书!《永乐大典》首次线上公开 免费看
华擎推出4X4 BOX-7000系列迷你主机:锐龙7000U、支持双USB4
小米Civi 2宣布全版本支持MIUI 14!系统丝滑流畅、更省电
女子手机放枕边突然冒烟自燃:曾因进水维修
饭店反向抹零多收1毛被罚4500元 网友点赞:四舍五入抹零有误都可举报
天天日报丨必知必会的设计原则——里氏替换原则
焦点速递!联想发布“问天”服务器品牌 向3S领域发起总攻 5年内冲击第一
焦点!谷歌版ChatGPT灾难级发布 市值一夜狂跌7000亿 熬夜网友:退钱!
快播:刘强东要建员工福利房?京东31亿北京拿地 1.6万元/平
当前快报:手工扯面+秘制辣油 西安饭庄油泼biangbiang面6.6元/盒大促
全球看点:任天堂港服“任亏券”开卖:《塞尔达传说:王国之泪》预售你买没
孔雀石的主要成分是什么?孔雀石的作用与好处有哪些?
空气能热水器的优缺点是什么?空气能热水器十大名牌排名
高一选科怎么选最好?高一期中考试总结范文
暑假带孩子去哪里旅游最好?我的快乐暑假作文模板
旅游高峰期相反的叫什么?旅游高峰期是哪几个月?
植物大战僵尸2闪退是怎么回事?植物大战僵尸2闪退解决办法
精彩看点:【学习笔记】Http请求方法总结
当前通讯!FCoE简单介绍
头条焦点:git在工作中如何使用?
热议:近期做的有意思的两道题,不知道是谁抄谁hhhhh