一次偶然的并发

事件背景

算法使用c++封装为sdk,外层使用go搭建服务,使用cgo加载so进行跨语言调用。

sdk实现过程中,使用proto传输数据之后,需要转为CVMat,然后才进行推理。

追踪之后,发现在proto字节数组进行CVMat的解码消耗巨大,大约占据核心推理的 1 3 \frac{1}{3} 31时间。

导致封装服务QPS大约下降 25 % 25\% 25%

基本限制

  • sdk的方法,是串行的,不能并发调用

  • 跨语言调用必定需要数据传输,数据转换必然存在

  • 全套使用c++开发,得不偿失,方案废弃

# 解决思路

  • 启动多个实例

每个实例仍然存在消耗,废弃

  • 多线程解码

使用c++进行多线程编程比较麻烦,不好管理,增加代码复杂度。

同时,外部的入口唯一,多次请求才可能进入多个数据,并发条件并不成立。

最终方案

go直接进行sdk的并发调用,然后对sdk中的核心推理部分进行加锁。

由于是并发调用,多个请求都会进行直接进入到sdk中进行操作,CVMat编码部分都会进行操作。

但是由于锁的限制,每次都只会存在一个请求进行核心推理操作。

这样一来,c++部分只添加了三行代码

  • 头文件
  • 锁声明
  • 上锁

至于go的并发,就当是个笑话。

新的视角

一般来说,并发是这样的

共享的资源,或者说是有限(单一)的生产者,然后对应多个的消费者。

这种情况下,关键在于共享资源状态的一致性。每个消费者触发消费的时候,全体消费者对于资源的一致性认可。

一般的的卖票的例子就是这种情况,比较特殊的是上厕所,这种表现的是状态的长时间保持,也就是资源的独占。

但是更显著的特征是,方向性。这是消费的过程。


同时,并发的根源性问题,引申出一个关键的补充信息----效率同步

为了提升效率,我们才使用的并发,如果任务当中存在快慢的差异,针对慢的部分,我们仍然会考虑并发。

使用更多的消费者去加速这一段慢的操作,去平衡两边的速率,去逼近最优的解。

这样,就出现了任务的阶段化的拆解。

比如nettyreactor模型,接收的group不多,甚至唯一,但是处理线程是多个。

最常见的就是服务集群了,高可用是一方面,但是对于处理较慢的部分,多个实例消费,也是原因之一。


如果说消费是太阳一样的放射的话,从相反的角度来看,就会是像漏斗一样的汇聚流程。

好比银行柜台填表,亦或是升学。下面的多个实例,进行层级的过滤,然后产出(进行)主要的成果(操作)。

更贴切一些,我们写数据库的时候,势必要保证数据的唯一性,也就是说,每次都是串行的。

但是服务层级上,我们或许都是并发操作。

前一种,是串行到并行,后一种,是并行到串行。

重中之重

两者之间的区别在哪里呢,或者说在于资质(资格)的评价。

  • 串行到并行

卖票什么的我们先放过,使用面试来进行对比,进行两种差异化的并发的统一。

当你通过面试,或者说录用之后,或许让你做前端、后端、前台…

数据处理的时候也是如此,根据内容然后进行不同阶段的操作。

在此,同样的角色,可以对应的是多个(种)的途径。

  • 并行到串行

同样的,入职之前,你必须通过多轮面试,多轮的资质校验。

HR,技术面,经理面…

然后你才能最终成为一个新员工。


也就是说,两者的统一对立面在于,我们是想得到,还是想处理这么一个东西。

大部分情况下,或者说服务开发过程中,我们都是去处理这么一个东西,为了更好更方便的处理,才使用的并发。

但是如果是获取的话,我们需要的是使用并发来进行基础操作,然后串行的收获果实。

统一的例子

使用池塘打水来举例。

一家人都去提水,每个人都动员。

对于池塘这个共享资源,每个人都在消费,这是并发。串行到并发。(当然,这个状态并不严谨,或者水井比较合适)

但是,一家人,汲水之后,放在哪里呢,肯定是倒在家里的水缸里。

此时,就是并发多线程汇聚单线程的操作了,肯定是要一个个来的。


因此,对于目标(共享消费的对象,或者汇聚的结果),我们必须保证串行,必须上锁。

而对于过程的不关注,我们就可以使用并发去进行快速的解决。

感想

这次的操作,就结果来说,的确是一个简单的并发案例,但是隐蔽的视角,让我感触良多。

主要的是,它的入口和操作唯一对应,也就是天然的似串行化

同时,我们更多的经验在于让一个任务并发处理,而不是让部分任务并发处理。

我们的任务经常都是经过拆解之后的独立任务,都是纯并发的处理方式。

同时,这是一种比较隐匿的锁的细粒度化,最外层的锁在于我们思维中的只能串行调用

但是真正的串行是推理,推理之前,我们并行无不可。

正是并发,跨语言调用,在真正的核心推理之前,由于串行而阻塞,但是资格审核都已通过CVMat解码。

【为什么学习这门课程?】 课程教授如何通过模式、面向对象设计技术和Java编程语言的特性来开发高质量并发软件应用程序和可重用框架。 多核的分布式核处理器、廉价的大容量存储、无处不在的连接性和通用软件平台的融合趋势,正推动着软件工程师和程序员的需求变化,他们需要知道如何为连接到云计算平台的客户端设备开发并发软件。尽管目前在处理器、存储和网络方面有许多改进,但是从客观上说,想要根据预算额度按时开发和交付高质量的软件仍然是有难度的,特别是开发高质量的并发软件应用程序和可重用服务。 【课程亮点】 本课程通过示例描述了如何通过使用面向对象的设计技术、Java编程语言特性、类库、应用模式和框架等技术要点,来有效降低并发软件开发的复杂性。课程中使用了许多Java应用程序示例来展示并发软件中的面向模式设计和编程技术。 【讲师介绍】 Douglas C. Schmidt(道格拉斯·施密特)—— ACE / TAO初始研发者、《C++网络编程》作者 施密特博士是ACE、TAO和CIAO的初始研发者,过去的20年里,领导了面向模式DRE中间件框架的发展。这些技术已被全球数千家公司和机构成功应用于许多领域,包括国防和安全、数据通信/电信、金融服务、医疗工程和大型多人在线游戏。施密特博士曾担任卡耐基梅隆大学软件工程学院的首席技术官,目前是美国范德堡大学(Vanderbilt University)的计算机科学教授。主要研究分布式实时和嵌入式系统的模式、优化、中间件和基于模型的工具。  施密特博士还是《C++报告》的前主编和《C/ C++用户》杂志专栏作家。发表了500多篇技术论文相关的话题, 主要涉及模式、优化技术、面向对象的框架和实证分析和特定领域的建模环境。与人合著了四本模式领域的经典书,包括《C++网络编程》第一卷和第二卷、《编程设计中的模式语言》、《面向模式的软件设计》。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值