整理速度比公式.docx

上传人:b****7 文档编号:11023992 上传时间:2023-02-24 格式:DOCX 页数:14 大小:26.51KB
下载 相关 举报
整理速度比公式.docx_第1页
第1页 / 共14页
整理速度比公式.docx_第2页
第2页 / 共14页
整理速度比公式.docx_第3页
第3页 / 共14页
整理速度比公式.docx_第4页
第4页 / 共14页
整理速度比公式.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

整理速度比公式.docx

《整理速度比公式.docx》由会员分享,可在线阅读,更多相关《整理速度比公式.docx(14页珍藏版)》请在冰豆网上搜索。

整理速度比公式.docx

整理速度比公式

 

速度比公式

20年月日

A4打印/可编辑

 

标题页

网络算法学是作者针对网络计算机系统的高效实现提出的一组一般性原则,因此本章可以说是本书的精华。

这些实现原则总共有15条,是从比较成功的案例中归纳出来的。

其实很多人已经有意无意地使用了这些原则,本章只是更清楚地将它们表达出来,以使我们可以更加主动地去运用它们。

本章首先用两个例子来说明如何利用原则来优化解决方案,给读者一个初步的体验。

3.1运用实现原则的例子:

更新TCAM

使用TCAM进行IP地址査找

图3.4是TCAM用于IP地址查找的例子。

IP地址前缀是长度为32比特的三态字符串,通配符都在字符串的尾部。

我们稍微改变一下表示法,使得*表示任意数量的通配符。

按照TCAM的工作原理以及最长前缀匹配的要求,TCAM中的地址前缀必须按照前缀长度从大到小的顺序排列。

路由表是动态变化的,如何在TCAM中添加或删除一条地址前缀,与此同时仍然保持前缀长度从大到小的排列顺序?

假定在图3.4的TCAM中需要添加一条新的前缀11%假定TCAM是向上扩展空间的,最朴素的方法是在长度为2的询缀表项中插入询缀ir■,比如插在前缀0*的前面,为此,需将前缀10*至前缀010001*整体向上移动一个位置。

对于包含大量路由表项的路山器来说,这种更新的速度太慢了。

有没有快一点的方法呢?

我们再来看一下图3.4的前缀排列方法:

长度相同的前缀排列在一起,按照从长到短的顺序排列,并且相同长度的前缀按照大小进行了排序。

首先,相同长度的前缀是否需要排序?

事实上,相同长度前缀的顺序对于TCAM执行最长前缀匹配不是必须的,因为一个IP地址不可能同时匹配两个相同长度的前缀。

我们只需要按照前缀长度进行排序,并不需要相同长度前缀之间排序,因此这是一个可以利用的自由度。

理解并利用自由度

(1)

利用该自山度,我们可将11*插入到00*和11广之间。

当然,如果为此将111*及以上前缀向上移动一个位置,则不会有多大优化的效果。

我们的想法是将口丁移出,将1广插入11广的位置,然后再为口广寻找一个插入位置。

尽管这个问题和原来的差不多,仍然要向TCAM中插入一条前缀,但是问题的规模缩小了一点。

理解并利用自由度

(2)

我们可以将这个方法推广:

•••••.。

显然我们可以采用递归的思想来设计一个算法。

使用算法技术一采用递归

实现的时候展开递归:

......。

如果每一种长度的前缀都有(即最坏情况),需要(32-i)次访存。

对于较小的i,访存次数接近32。

这个算法已经比朴素的算法好了很多,但是不是最好了呢?

还能减小最坏情况下的访存次数吗?

(想一想)

我们再来看这张图,这张图假设空闲空间在TCAM的顶部,实际上空闲空间可以放在TCAM的任何地方,因此空闲空间的位置也是一个设计自由度。

进一步利用自由度

利用这个自由度,可以将空闲空间放在中间,比如放在长度为16的前缀项后面,这时最坏情况下的访存次数可以减少一半。

当然,空闲空间的数量也可以是一个自由度,可以进一步减少最坏情况下的访存次数。

除了空闲空间的位置及数量之外,还有没有可以利用的自由度了呢?

再回到slide4,长的前缀是否一定要出现在短的前缀之前?

比如,010*能否放在111001*之前?

完全可以,因为不可能有一个地址会同时匹配这两项。

一个更复杂的自由度是,"如果i>j,那么长度为i的前缀必须岀现在长度为j的前缀之前〃,这是一个充分条件,但不是必要的。

一个不那么严格的要求是,"如果两个前缀P和Q可能匹配同一个地址,且P比Q长,那么P必须出现在Q之前〃。

这样修改规范后,可以进一步减少最坏情况下的访存次数。

缺点是提高了复杂度。

这个例子所用的原则叫做优化自由度,就是不断地寻找和利用自山度来优化实现。

当然并不是所有的自山度都要用起来,比如自山空间的数量、长的前缀可以放在短的前缀之后等,这些自111度是否值得利用需要权衡利弊。

这个例子就是告诉我们要放开去想,尽可能地去寻找可以改变的量,帮助我们一步一步地不断完善我们的解决方案,努力做到最好。

3.2算法vs算法学

第一个例子主要是在算法层面上考虑,下面的例子说明算法与算法学的差异。

举例:

安全物证问题

假设一个入侵检测系统通过统讣流量来检测异常节点,比如在一个测量周期内发现一个节点向网络中的不同机器发送了10万个包,就确定这个节点在进行端口扫描攻击。

当判定某个节点为攻击源时,要将该节点在测量周期内发送的包写入安全物证日志,供管理员进一步分析。

如何检测攻击不是我们要讨论的,我们关心的是当判定某个节点为攻击源时,如何得到它已经发送过的那些包。

解决方案

为实现此目的,我们维护一个包队列,当一个数据包被转发时,路由器将该包放入队头。

为限制队列的长度(路由器的内存是有限的),当队列满时,删除队尾的包。

该方案的主要困难是,当检测到一个可疑流时,该流已经有大量的数据包在队列中了,并且和大量其它的包混在一起。

如何高效地从队列中找到属于可疑流的所有包?

最相素的方法是顺序搜索队列,这显然非常低效。

我们一般会采用什么方法,快速找到流F的数据包呢?

教科书上的算法

教科书上的算法会构造某个索引结构来快速搜索流ID。

比如,我们可以维护一个流ID的哈希表。

......

但是该算法仍有问题。

它需要额外的空间来维护哈希表和指针列表,而对于高速实现来说存储空间是非常宝贵的。

它还增加了包处理的复杂度,需要维护哈希表。

这个算法的问题在哪里?

为什么我们要对每一个包进行归类?

这是因为我们潜意识里假设每一个流都有可能是可疑流,因此每一个包到来时都将其分到相应的流中,这样一旦某个流被认定是可疑流,立即就可以得到属于该流的所有数据包。

但事实上,在真实的网络环境中可疑节点只是少数,比如儿万个节点中只有一个是异常的,但我们儿万个节点发的包都做了归类,这里面我们做了许多无用的处理。

这是显而易见的浪费!

那么我们怎么可以避免做无用功呢?

联想到我们前面举过的例子(检测异常URL),我们可以采用推迟计算来解决这个问题。

推迟计算的要点是,不急于做高开销的工作,直到不得不做的时候再去做。

系统的解决方案

基本思想:

将判断一个包是否属于可疑流这件事情,拖到不得不做(发现可疑流,且包将移出队列)时再去做。

什么时候不得不做?

(2)发现了可疑流;

(2)数据包将移出队列

令路山器转发包时统讣每个流(节点)发送的包数。

当流F发送的包数超过一个阈值(如10万)时,将流F添加到可疑节点列表中。

当可疑节点列表非空且队列满时,每当往队列中添加一个包,就从队尾中移出一个包,判断该包是否属于Fo若属于F,将该包(或指针)拷贝到物证日志中;若否,将该包丢弃。

该方案不需要维护哈希表和指针列表,节省了大量的存储空间和计算开销。

这个例子使用了两个原则,一个是避免显而易见的浪费,另一个是在时间轴上移动计算。

3.3十五条设计原则

第一章的例子(设计一个检测异常URL的芯片)和前面这两个例子给了我们有关网络算法学的一些初步体验。

下面介绍作者归纳的15条原则,以及实现这些原则的一般技术,这15条原则我们会不断地使用。

这15条原则可以分为三类:

1.系统原则:

®1-5条原则利用了系统思想,它将系统看成是曲子系统构成,而不是一个黑盒子。

2.兼顾模块化和效率:

第6-10条原则允许保留复杂系统的模块化,与此同时给出提高性能的方法。

3.加速:

笫11-15条原则提出了加速某个关键功能的技术(仅考虑该功能本身)。

每条原则作者都有一个例子来说明,具体细节将在后续章节中讨论。

P1:

避免常见情形中的明显浪费

在一个系统中,在一些特殊的操作序列中可能存在资源浪费。

如果这些模式经常出现,就有必要去除这个浪费,这样可以从整体上降低系统的开销。

编译器的例子:

消除重复的子表达式。

经典的网络例子:

操作系统和用户空间之间多次数据包拷贝(第五章介绍)。

这条原则看起来容易做起来难,最难的是如何发现明显的浪费。

第一章检测异常URL的例子中,对于每个URL都清除一遍讣数器数组C,还有本章的第二个例子,对于每个收到的包都进行归类,这都是明显的浪费,但并不是很容易发现。

这需要领域知识,也需要有系统观才能发现(比如,异常节点是少数,包缓存队列长度有限)。

P3:

放宽系统要求

一个复杂的系统总是从上到下进行设计,先将功能在子系统间划分,在确定了子系统的需求和接口后,再设计每一个子系统。

在设计的时候不一定完全了解实现的难度,当遇到实现困难时,有些方面的要求要改变。

如图3.8所示,一个系统由两个子系统组成,子系统2对子系统1的实现要求称为规范S。

如果子系统1实现困难,有时可以要求降低对其的实现要求,即要求子系统1遵循较为宽松的规范Wo

在第1章的例子中,由于设计除法电路(subsystem1)比较复杂,改用移位代替除法,也就是放宽了子系统1的实现规范(S->W):

子系统1只需实现移位操作而不是任意的除法操作。

其代价是子系统2必须遵循更强的特性(P->Q):

门限须用2的幕次表示,而不是一个任意的浮点数。

P3a:

牺牲确定性换时间

超级节点的检测:

确定性的方法是统计以每一个节点作为源(或目的)的数据包数量,这需要检查每个包的源地址(或LI的地址)进行统讣,这在高速网络中是做不到的。

随机化方法是每隔一定数量的包统汁一次,虽然不能保证口分之白正确,但在很大概率上是正确的。

P3b:

牺牲精度换时间

图像压缩是一种很耗时的操作,对于实时视频要求压缩速度很快。

离散余弦变换可将信号能量集中在少数儿个变换系数上,然后只需对主要的变换系数进行量化编码,达到快速压缩的目的。

但是图像质量(精度)会受到一些影响。

P3c:

在空间中移动计算

在空间中移动计算是指将计算从一个子系统移动到另一个子系统(注意和前两条原则的不同)。

比如,数据包分片会影响路山器的乔吐量‘IPv6将分片的功能从路由器移到了源节点。

为此,源节点主动探测端到端路径上的MTU,确定合适的分组大小,路山器不再提供分片的功能。

这样就简化了路山器的实现。

当然,这里的移动已经超出了一个网络设备的限制,是在整个网络中的移动(如果将网络看成一个系统,则路由器、主机就是子系统)。

P4:

利用系统组件

系统设计采用黑盒视图,就是将系统分解为若干子系统,然后独立地设计每一个子系统,而不去关心其它子系统的内部细节。

尽管这种自顶向下的方法具有很好的模块化,但实际上,性能关键的组件在构建时通常部分地采用"自底向上〃的方法构建。

比如,要在一个硬件上设计算法,通常要让算法适应硬件的特性,而不是让硬件来适应算法。

系统组件就是系统中的硬件,我们的软件要充分利用它们的特性。

P4b:

用空间换速度

一个显而易见的技术是用较大的空间来减少计算时间,比如将函数计算变为查表。

一个不那么显而易见的技术是用较小的空间来提高速度。

比如,把一个很大的数据结构压缩到可以放入cache,或者大部分可以放入cache,可以极大地提升系统速度。

当一个表的规模很大时,该技术特别有效。

有人可能会问,空间和时间都节省了,怎么会有这样的好事?

是什么增加了呢?

事实上,计算复杂度是增加的。

比如,访问压缩的数据结构,其处理复杂度是提高的。

但由于现代处理器的计算速度比访存速度快得多得多,在多核处理器上这个差距更大。

在这种情况下,适当增加计算复杂度并不会使处理器成为瓶颈,却因为提升了访存速度使得系统整体性能得到提升。

这是实践中用得很多的一种优化技术。

使用这条原则的时候,一定要很清楚性能瓶颈在什么地方,是计算还是访存?

如果讣算是瓶颈而访存不是,那么通过适当增加内存访问来减少计算是可行的。

如果访存是瓶颈而计算不是,那么想通过减少计算来提高速度是不可行的,通过适当增加计算来减少内存访问是合理的。

这个需要充分利用系统硬件(处理器、存储器、总线等)的能力,平衡计算和访存。

如果P4原则使用过度,系统的模块化将受到损害。

为此需要注意两个问题:

(1)如果我们利用其它系统特性只是为了提高性能,那么对那些系统特性的改变应当只影响性能,不影响正确性。

(2)我们仅对确认为是系统瓶颈的组件运用该技术。

总的来说,对系统的优化要有一定的度,不是越多越好。

对系统修改越多,可能产生的不可预知的相互作用就会增多,可能会对系统的正确性产生影响,所以应当只对系统做最小的修改(不提倡大刀阔斧的改)。

P5:

增加硬件提高性能

当所有的方法都不奏效时,增加硬件(如使用更快的处理器、存储器、总线、链路等)可能是更简单和有效的方法。

然而,硬件毕竟成本比较高,即使需要增加硬件,我们也希望只增加最少的硬件。

这就要求充分挖掘软件的潜力,把软件的性能做得极至。

随着处理器的速度越来越高,存储容量越来越大,特别是多核处理器的出现,我们发现软件算法设计得好的话,也是可以运行得很快的。

因此,一种比较理想的情况是,用软件实现关键的算法,然后通过处理器的升级自然获得速度的提升。

将功能在硬件和软件之间划分是一门艺术。

一般认为,硬件缺乏灵活性(不容易增加新的功能),且设计成本高、周期长,适合完成较简单的、较固定的功能。

软件灵活性好,可以很容易地移植到新的、更快的处理器上,获得性能提升。

但是动态可重构技术的出现使得这种界线在逐渐模糊,利用动态可重构FPGA实现的系统,既有硬件的执行速度,乂有软件的可编程性,可以执行复杂的功能(可重构处理器),设计工具的出现也使得硬件设计周期大大缩短了。

现在有更多的硬件可以使用,计算硕件有GPU、NPU、TPU、ASIC等,甚至智能网卡可将一些计算卸载到网卡上完成,存储器件有闪存Flash.固态硬盘SSD等。

是否增加硬件、增加什么硬件,需要从性能、功耗、成本等各方面考虑,我们的决策需要随着技术的发展而变化。

以下特殊的硬件技术通常用于网络ASIC芯片中。

P6:

用高效的定制例程替换低效的通用例程

通用性和高性能通常是一对矛盾。

通用性要求兼顾大多数情形,一般来说就不会针对某种情形进行特殊设计。

所以一个通用的东西一定不是最高效的。

比如,操作系统的cache替换策略是LRU,将最长时间未被访问的数据记录替换岀去,这么做符合一般的程序运行模式(局部性原理)。

然而,考虑一个查询处理例程,它在处理一个数据库查询请求时,需要依次地处理一系列的数据库记录。

在这种情形下,最近使用过的数据库记录恰恰是最不会被再次访问的,因此应当选择这样的记录替换出去。

正因为如此,许多数据库应用都用定制的缓存例程替换了操作系统的缓存例程。

这里需要兼顾模块化,为避免代码膨胀,最好只对关键的例程进行定制化。

P7:

避免不必要的一般性

设计一般性的子系统可能导致不必要的或者很少使用的特性,当应用场景固定时,可以移除一些不必要的特性来提高性能。

这里也是通用性和高性能之间的权衡。

P6是重新设计一个定制例程,P7是去掉一些不要的特性。

P8:

不要受参考实现的束缚

我们实现一个协议或系统时,都要遵循相应的规范。

规范是解释性的,主要解释概念、功能、流程等,并不包括实现。

规范应当使用规范语言来书写,但是因为规范语言用得不普遍,许多规范会用命令式语言(如C语言)给出,即参考实现。

这些参考实现给出了如何实现功能的代码。

这会带来两个副作用,一是描述过于详细(规范应当只是说明要做什么,不应包括怎么做),二是实现者可能直接将参考实现代码拷贝到自己的系统中。

但是,参考实现代码只是为了解释概念,并不关注效率,因此直接使用参考实现会非常低效。

P11:

优化预期情形

尽管系统可能会呈现出很多种行为,但是大部分情况下,系统的行为是可预期的。

比如,一个设计良好的系统大部分时间工作在无故障的状态;网络中的数据包大部分情况是按序到达的,并且没有出错。

我们有必要去优化这些常见的情形,哪怕使得非预期情形的处理变得低效。

举例:

最早的TCP处理程序耗时很高,分析代码发现它完全是按照一般的协议处理情形来写的,需要判断很多状态来处理各种情形。

但实际上这些状态检查对于大多数TCP包来说都是不必要的,大多数TCP包都是按照预期到来的,比如具有预期的字节序号、预期的确认序号等。

工程师们优化了程序实现,首先判断TCP包是否是预期的包(预期情形),如是则不再检查其它的状态,如果不是再按照原来的流程处理,极大地提高了处理速度。

这个技术称为TCP头部预测。

优化常见情形的方法通常称为启发式方法。

启发式方法是一种根据经验规则进行发现的方法,其特点是在解决问题时利用过去的经验,选择已经行之有效的方法,而不是系统地、以确定的步骤去寻求答案。

启发式方法是与算法相对立的,算法是把各种可能性都一一进行尝试,最终找到问题的答案,但它是在很大的问题空间内、花费大量的时间和精力才能求得答案。

启发式方法则是在有限的搜索空间内,利用很少的搜索次数迅速达到问题的解决。

但山于这种方法具有尝试错误的特点,所以也有失败的可能性。

确定常见悄形主要依幕设计人员的直觉,也可以通过测量工具来发现。

P12:

增加或利用状态

如果一个操作的代价很高,可以考虑维护额外(冗余)的状态来加速该操作。

数据库中的一个典型例子是使用辅助索引。

比如,银行记录可能使用客户的身份证号作为主键进行存储和查找,但是很多时候需要根据客户名字进行查询。

为了加快这种操作,需要利用客户名字建立另外一个索引(如哈希表、B-树)。

维护额外的状态意味着当状态有变化的时候,额外的状态也要更新。

有时候可以不增加新的状态,而是利用已有的状态,这种技术称为增量计算。

比如,在计算IP头检验时,头部只有儿个域有变化,可以进行增量计算(不需要对所有的域计算检查和)。

P13:

优化自由度

知道哪些变量在我们的控制之下,对于我们进行系统优化是很有帮助的。

我们的问题就变成了:

优化这些变量以最大化性能。

在这里变量就是自III度,就是可以由我们改变的因素。

使用这条原则的关键是找到可以优化的自山度,即找到优化的方向。

P15:

利用算法技术构造高效的数据结构

作者终于在最后一条原则中提到了算法技术。

在有些悄形中,高效的算法肯定可以极大地提高系统的性能。

但是作者指出,在考虑算法之询需要先运用P1~P14原则对系统进行优化。

换句话说,在其它问题没有解决前,算法通常不是瓶颈。

因此我们在科研实践中,应当先考虑数据路径上其它方面的优化。

在所有其它问题都解决后,剩下的才是算法问题。

经常有学生觉得,不做算法就不算做研究,做的工作就没有技术含量。

实际上对于一个实用的系统,不是比谁的算法复杂,而是看实际效果。

简洁优雅的解决方案最受青睐,因为这样的工作离实用最近。

所以我们在做系统实现或优化的时候,在达到相同效果的前提下,要追求方法简单。

这也是操作系统中很少用复杂算法的原因,太复杂的算法会影响系统的稳定性和可靠性。

算法方法包括使用标准的数据结构,以及一般的算法技术,如分治和随机化。

然而,算法设讣者必须做好这样的心理准备,就是其设计的算法可能随着系统结构和技术的变化而被淘汰。

真正的技术突破可能来自算法思维的运用,而不仅仅是重用已有的算法。

3.4—些警告

在运用原则前,必须理解重要的性能指标,确定系统瓶颈。

在完成改进后,必须通过实验来确认改进的效果。

下面用两个例子进行说明。

案例:

减少网页下载时间

在图3.8中,web客户欲从服务器获取内嵌有图像的一个网页。

典型地,客户先发送对网页的GET请求,然后针对内嵌的每个图像分别发送GET请求。

对原则P1(消除明显的浪费)的自然运用是:

为什么服务器不自动将图像和网页一起发送给客户,而要等待客户的请求呢?

这应当可以减少网页的下载延迟。

为了测试这个猜想,作者修改了服务器软件,令服务器自动发送图像给客户,然后测量性能。

出乎意料的是,网页下载延迟的改进很微小。

使用一个基于tcpdump的网络分析工具,作者发现有两个原因导致这个看似不错的改进方法是个坏主意。

(1)与TCP的相互作用:

web传输建立在TCP之上。

TCP在新建立的连接上使用慢启动发送数据包:

首先发送一个TCP段,在收到确认后发送两个TCP段,在收到ACK后逐步提高发送速度。

因此,即使令服务器主动发送图像,发送端TCP也必须等待ACK来提高发送速度,这和等待客户的图像请求没有多大的区别。

(2)与内容缓存的相互作用:

许多客户端有缓存功能,一些常用的图像会缓存在本地,因此令服务器主动发送已经缓存在本地的图像是对带宽的浪费。

如果让客户发送请求,则客户对于已经缓存在本地的图像不会发送GET请求。

这个例子给我们的教训是,如果不了解系统各个部分之间的相互作用,改进的效果可能达不到我们的预期。

而系统优化的困难之一也是系统的各个部分之间存在复杂的相互作用,很多时候我们不能清楚地理解这些相互作用,这时候实验验证就很重要了。

八个提醒注意的问题

作者提出以下8个需要注意的问题,避免不恰当地运用实现原则。

Q2:

这确实是一个瓶颈吗?

80-20规则表明,80%的性能提升来自于对系统20%的优化,因此只需要找到最关键的瓶颈就行了,其它次要的问题可以不用管。

这可以使用如Oprofile这样的工具来发现。

Q4:

初步分析表明会有重大的改进吗?

在动手进行一个完整的实现前,快速地分析一下可以获得多大的收益,以避免做无用功。

对于终端系统而言,山于访存是最大的瓶颈,因此用访存次数做为粗略的估计是合理的。

Q5:

值得增加定制硬件吗?

通常认为定制硬件设计周期长,开发成本高。

随着通用处理器性价比的不断提高,一种非常有吸引力的做法是用软件实现算法,依靠通用处理器来获得高性能,避免定制硬件。

但是,随着高效的芯片设计工具的出现,定制硕件的设计周期在缩短,批量生产也极大地降低了成本(与通用处理器相比),所以也有越来越多的公司将网络功能放到芯片中实现。

Q6:

能够避免协议的修改吗?

这些年来,当一些协议运行较慢时,就有人怀疑是协议设计得不好,从而去研究可以提高性能的新协议。

比如,上世纪80年代,有人认为TCP协议很慢,并提岀了一个可用硬件实现的XTP协议。

这项工作刺激了TCP/IP开发人员去研究TCP的高效实现,最终导致快速TCP实现在标准的BSD操作系统中发布。

为解决IP地址查找慢的问题,有研究工作提岀修改IP协议、加入标签和流交换机制。

这项工作激发人们去研究快速IP地址查找。

如果仅是为了提高性能而修改协议,我们不妨去研究如何高效地实现协议。

Q7:

原型系统验证了最初的设想吗?

一旦我们成功地回答了以上问题,我们还需要建立一个原型系统或进行仿真实验,确认性能真的提高了。

这是因为我们面对的是一个复杂系统,最初的分析很难把实际中遇到的问题都考虑到。

案例一和案例二都形象地说明了这个问题。

一个主要的问题是寻找一组标准检测程序(benchmark),以标准实现和新的实现进行比较。

Q8:

性能收益会因为环境改变而失去吗?

即使原型系统实现了,并且标准检测程序也表明性能提高与最初的设想接近,我们的工作也还没有完。

这里的问题是,性能的提高可能和使用的特定平台(可能改变)有关,也可能利用了特定的标准检测程序的特性(标准检测程序不可能反映系统所处的所有环境),进行一个墩感性分析是很有用的。

整理丨尼克

本文档信息来自于网络,如您发现内容不准确或不完善,欢迎您联系我修正;如您发现内容涉嫌侵权,请与我们联系,我们将按照相关法律规定及时处理。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 党团工作 > 思想汇报心得体会

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1