2022年全球C++及系统软件技术大会参会报告

举报
飞得乐 发表于 2022/09/30 19:36:44 2022/09/30
【摘要】 因为疫情的原因,C++技术大会时隔一年半之后才得以再次举办。这是我第3次参加该会议了,在前两次会议中,我发现国外专家的主题演讲大概率会有更高的质量,所以这一次我干脆全部听的国外专家演讲。主办方也很贴心,直接把所有的英文演讲全部排在了C会场。下面介绍我这次会议听的主题:《现代C++的发展与演化》——Bjarne StroustrupC++之父的演讲照例排在第一个。但实际上Bjarne每年讲的几...

因为疫情的原因,C++技术大会时隔一年半之后才得以再次举办。这是我第3次参加该会议了,在前两次会议中,我发现国外专家的主题演讲大概率会有更高的质量,所以这一次我干脆全部听的国外专家演讲。主办方也很贴心,直接把所有的英文演讲全部排在了C会场。

下面介绍我这次会议听的主题:

《现代C++的发展与演化》——Bjarne Stroustrup

C++之父的演讲照例排在第一个。但实际上Bjarne每年讲的几乎都是同样的东西:自己创造C++语言的过程、C++的原则、发展方向、语言特性的发展历程、C++成功的原因……也容易理解这些东西不得不讲,因为每年都会有新人参会,他们还是很需要听一遍这些知识的。要说今年讲的和往年的最大区别,就是介绍了C++23和26两个版本预计会有什么特性。

在提问环节,Bjarne回答呈现的一些观点反而比较有意思:

首先是语言战争(language war)。面对这个话题,Bjarne直截了当的表示自己早就“身经百战”了,一路从Fortran、LISP、Java、Go、Rust……等众多语言的围追堵截中打过来,Bjarne表示根本不care什么语言战争。他说当年Java出现的时候就大肆宣传过要在两年内干掉C++,现在这种言论出现在别的语言上也没什么稀奇。Bjarne说,他私下和Dennis Ritchie等其他语言创造者都是好朋友,正确的态度应该是语言之间互相学习和借鉴,而不是战争。

谈到Google新发布的语言Carbon,Bjarne说那就是一小撮人在弄的玩意儿,我们等着瞧看他们能不能弄出个真正的语言出来。

谈到日益壮大的Rust,Bjarne说未来Rust有发展空间,但C++同样也有发展空间。

有人提问为什么C++不像Java、Go那样背靠一个大公司进行推广。Bjarne开始哭穷,讲述了C++委员会没钱的现状,连个秘书都请不起。Bjarne说C++从来就没有钱做推广,能够壮大都是因为使用C++的用户求着他们一定要维护下去,否则自己巨量的存量代码没法玩了。但是背后没有金主也给C++带来了好处,比如没有一个money manager来干涉语言的发展方向,C++委员会也不用为了市场而追时髦。

有人提了一个技术问题:在嵌入式系统上,怎么解决C++编译出的目标文件很大的问题。听到这个问题,Bjarne觉得不可思议,他说除非你大量使用异常,否则目标文件应该非常小才对,C++是非常适合嵌入式的。主持人补充说是因为模板,Bjarne再次连连摇头,说模板导致的目标文件膨胀,唯一的原因是不当使用虚函数。如果没有在模板中使用虚函数,那么根据他的经验,生成的代码都会被优化掉,不会有目标文件过大的问题。最后Bjarne还强调不要去猜测性能,要实际测试,他说他见到的喜欢猜测性能问题的人太多了。

最后谈到了教育,Bjarne表示现在的C++教育方法是错误的。很多人认为要先学C语言再学C++,这在他看来完全错误。Bjarne认为,学C++要先从语言的主要思想开始学,而不是总想要掌握所有的语言细节。太多人的学习方法是想成为一个语言律师(language lawyer)而不是成为一个开发者。Bjarne自己写的C++教材只有不到200页,他说自己的书直到第17章才讲到指针,因为大多数的C++编码根本用不到指针。

《RCU无锁编程探究与实践》——Paul McKenney

Paul首先讲了物理定律:光(或者电信号)在一个CPU时钟周期内可以跑多远?最后计算出来的,是非常非常短的距离(大约一两厘米)。在之后的多线程代码中,他指出这个物理定律造成了多核编程中的漏洞(loophole),即read发生在store之后,但是数据从一个CPU核跑到另一个CPU核需要传播时间,导致结果仍然非预期。

为了解决数据同步造成的不确定结果,需要经常使用同步原语,但这又带来了性能开销。RCU库使用了一种同时利用时间和空间的方法:复制数据,在新副本中修改,再释放旧数据。这种方法在一定条件下相比传统的同步有了显著更好的性能。

有人提问:你怎么保证删除旧数据的时候,其他线程都已经读完了?Paul表示这依赖于Linux内核中的很多dirty detail,因此RCU不是C++标准中的方法。

《大规模软件性能设计与实践》——Fedor Pikus

Fedor是EDA软件的架构师,他指出性能评估必须基于度量,但是软件设计必须考虑性能,接下来就产生了悖论:设计阶段还没有代码,怎么度量?接下来的例子中,Fedor展示了软件设计需要注意的性能影响点:确定主要性能目标、考虑数据组织方式、接口定义、为实现优化留下空间。他指出:虽然设计阶段没法直接度量性能,但是你的API设计直接影响了后续的性能优化空间。因此做设计时,一定要确定合理的API,尽可能多的隐藏数据细节,这样后续才有充分的自由度做优化。

《拥抱C++20元编程》——Kris Jusiak

Kris的演讲几乎全是代码,首先介绍了C++20中怎么实现fix_string(把string作为模板非类型参数),然后讲了怎么用全模板编程的方法做一个状态机定义DSL。通过C++20的Ranges特性,编译器可以对类型进行计算。因此把状态、动作、消息全部类型化以后,结合操作符重载,最后就可以像写DSL一样的写状态机。而且由于所有的状态定义都在编译期模板运算后生成代码,因此性能非常好,远高于传统的状态查表、函数指针等状态机实现手段。

恰好我这段时间也在想能否用元编程来做状态机,Kris大神弄出的这套玩意儿在很多业务场景下应当会有市场。

《高质量代码生命周期的思考与实践》——Phil Nash

Phil的主题是讲软件质量,但是他的质量定义方法和国内很多专家截然不同:他从头到尾不提任何指标,也没说编程规范和静态检查,反而把重点放在了代码的设计方式上。Phil对比了代码处理异常输入的各种方式:参数检查、抛出异常、强类型……最后他提出可以用提供两套接口的方式——一套不进行参数检查,信任调用者;令一套进行全面的检查。这有点类似memcpy和memcpy_s两个接口同时提供的思路。

之后,Phil指出软件质量中很重要的一个方面:简洁(simplicity)。他说,只有简洁的代码才能有效的校验逻辑。要做到简洁,有多线程、可变性、依赖、抽象泄露等很多方面需要考虑。Phil重点用可变性举了几个例子,他认为大多数人声明变量时没有默认加const,这是非常不好的习惯。一旦你的变量是可变的,那么逻辑复杂度会立刻高很多,我们应该尽可能使用不可变的常量。

最后总结时,Phil摘出一篇文章中的话:有一些方法的确可以提高软件质量,当我们观察这些方法时,我们发现这些方法的共同点是:所有这些方法都迫使我们反思自己的代码(reflect on our code)。


《风险指针(Hazard Pointer)无锁编程精要》——Maged Michael

Maged在讲座中介绍了一种读写锁的替代品:使用风险指针。其原理是当线程要改写对象时,复制一份,修改新副本,然后在老副本被使用完后自动销毁。这个工具在folly开源库中实现了,且其中一部分已经提交给C++26标准。我乍一看时感觉:这不是昨天讲过的RCU么?到了结尾,Maged还真的把风险指针和RCU做了比较——他们各自适合的场景略有区别。

风险指针不需要任何同步机制,因此速度非常快,但是它用了专门的线程定时的检查废弃资源并释放,这和GC的方式异曲同工。非GC语言果然是常常向GC语言借鉴特性。以后C++标准中出现成型的GC特性估计也不会让人意外。

《C++内存与性能优化最优实践》——Michael Spertus

Michael的演讲风格很受喜欢,语速很慢,发音是标准的美式英语,演讲时都会由浅入深并且充分介绍技术背景,对于水平偏普通的程序员来说更为友好。这一次演讲中,Michael重点介绍了因为cache的存在所带来的性能优化问题,通过一个简单的并发计数器的例子,呈现了cacheline、锁等各种实现变化带来的性能差异。Michael演讲的主要内容都是围绕计算机体系结构中的成熟技术,并没有特别前沿的知识。但是最后提炼出的编码通用原则是很有指导意义的。

《使用内存分配器优化性能》——John Lakos

John的这场演讲很长,因此被分成了两段:上午最后一场和下午第一场。这可苦了在美国的John,他那边都讲到半夜1点了。最后快结束时,明显感觉John已经很困了,还是硬撑着回答提问。

演讲主要是围绕着John所做的大量性能测试,他总结了不同类型的程序在进行内存分配时所具有的不同时间、空间统计特征,从而设计出了多个各种典型的使用场景进行大量的性能测试。测试结果显示,在很多场景下使用局部分配器(local allocator)相比起默认的全局分配器都有显著的性能提升,有些场景甚至快10倍。最后John总结出了若干条内存分配器的选择建议,并且预言未来的C++标准库将会提供更多的分配器可以选择,而且用户接口也会越来越友好,甚至有些时候用户都不需要感知分配器的变化。

《Max功能实践:API设计、悬挂引用以及C++20 constraints》——Amir Kirsh

来自以色列的Amir所作的演讲非常特别,绝大多数时间里都在Compiler Explorer中现场“直播”编码过程。他觉得std::max有一些地方不够好用,比如不能对不同类型进行比较,有时候会返回悬挂引用等等,因此提出了改进的Max函数实现方法。

虽然Max是个很简单的比大小函数,但是一旦把左值、右值、引用、生命周期、类型转换、类型推导这些概念全堆上去,实现逻辑也变得相当复杂。在编码的过程中,有几次Amir甚至遇到了出乎预料的编译错误,自己也不知所措了,偶尔还向观众求助。我当时看的时候心也悬起来了:这家伙不会翻车吧?好在每次Amir最终都找到了问题的原因,顺利完成了演示。至于他展示的“改进版”Max是否一定比std::max好,我觉得很难讲。因为对不同类型做比较、用引用接收返回值等等使用场景并不是很常见,而且通常都有别的办法来解决。Amir更多的是展示了一种模板编程技巧。

《Windows、macOS and the Web:跨平台实践经验》——Sebastian Theophil

Sebastian在演讲中用几个简单例子说明了跨平台的实现是非常困难的事情。虽然Qt等库号称能跨平台,但是在很多常用的功能里,常常出现意想不到的错误。即使一个简单的临时文件操作功能,想提炼出真正好用的跨平台接口都困难重重。Sebastian将各种跨平台开发的经验教训总结成了9条Lesson,比如如何设计跨平台的API,如何在编译期尽可能的检查错误等等。最后他指出:跨平台远比你想的要困难,比起信任各种开源库,真正要做好还是得靠你自己的设计和封装。

《C++类型分类、陷阱与最佳实践》——Nina Ranns

Nina是C++大会上少见的女演讲者,作为国外的女演讲者我更是第一次见到。Nina是精通C++语言规定的标准委员会成员,她在演讲中并没有介绍前沿的创新技术,而是详细讲了从C++98到C++20的各个语言版本对于类型的约定。比如什么是aggregate,什么是trivially copyable等各种类型约定,在语言各个版本中都有些许差异,细究起来非常复杂。演讲中Nina还举出了几个未定义行为的例子,说这些代码虽然有未定义行为,但是事实上所有编译器都支持这么用,因此C++20把它给“修复”了,改为规定成有定义的。这也是C++标准的一个发展方向——逐渐采纳某些事实上的实现标准。

提问时我问Nina:靠人肉去校验标准实在太复杂了,有没有什么工具能检查代码不会有未定义行为?Nina回答没有办法,还是主要靠人。有一些静态检查工具可以查出部分的错误,但是还没有什么工具能保证代码不发生未定义行为。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。