美文网首页
毕竟人类

毕竟人类

作者: zizon | 来源:发表于2019-01-13 01:38 被阅读0次

考虑一种调用风格.

Promise.costly(()- >receive())
.transform((packet)- > mmap.transferFrom(packet))
.sidekick(()- >logging.info("saved"))
.catching((exception)- >logging.error("save fail",exception))
.addListener((channel)- >channel.close())

这里大致是对CompletableFutre和guava对ListeningFuture的一些包装.
稍微链式了一下,以及改动了点语义.

大致涵盖的几个data flow是.
一个正常情况下的receive packet - > save - > close.
一个sidekick是在正常receive之后的并行log部分.
一个是receive exception情况下的catching部分.
以及不管是正常还是异常情况下都并行触发的addListener部分.

最终返回的reference的value是跟transform返回的签名一致.
也就是除了transform,其他都是旁路性质.

这点跟completable是不太一样的.
虽然底层实际用的就是completable future.

这么做的原因主要是不想总是try catch.
或者像go一样检查返回值.

而且为了简单,lambda的声明都是带throw的对应的functional的版本.

所以实现上是把最初的exception一路propagate过来的.
这点跟completable/listening都算一致的.

问题主要是这个compute graph的trigger或者说traversal方式.
或者说transform这些callback的调用应该是同步还是异步的问题.

因为底层实际上就是Comp了table future.
所以实际上就是thenApply之类的调用的.

如果同步的话,实现上是会当场back trace的.

也就是当一个这个graph当中的一个stage完结之后会尝试看依赖项目是否也是可以执行.

这里的一个好处就是execution path可能尽可能地总体时间短.
因为基本上算是instant的.

这样的话,几率上来说对cache可能也会有点好处.

但这样的话为什么不直接写成正常的平坦的workflow呢.
而且可以没有那些基本的代价开销.

一个理由可能就是整体流程比较长.
或者存在一些不太确定的blcoking的部分.
所以通过这种人工的方式拆分出time slice.

某种程度上来说跟go的goroutine/chan/syscall调用时候隐切换是类似思路.
通过一种人为的软调度去提高throughput.

但是同时带来的一个问题就是可能latency相对会高一些.
因为是每个execution context的slice都会被切分并在不同的实际被queue或者stack.

所以,即使是说用async的方式处理stage.
但同样地还有是用first in first out还是last in first out的形式.

像Stream API的parallel使用的common pool就是forkjoin pool的last in first out.

这个在某种程度上来说是兼顾througput和latency的一个选择.
毕竟stack的距离可能没有queue的距离来得远,每个切换的数据访问的差异可能相对没那么大.

至少意图上来说,是有一定的cache friendly的.

但是这里同样会有个问题.

比如
LongStream.range(0,regions).paralle()
.mapToObject((region)- >file.map(region))
.flatmap((region)- >region.pages())
.map((page)- >crc.update(page))
.collect()
这类flatmap的stream generation.

可能隐式地来说,会有一个形式上的synchronize point.
因为pipeline的某个节点是generator,而generate的动作可能又是有一定开销的.
比如这里的mmap,基本上手受限于磁盘的.

这样的话forkjoin thread的local queue/stack就应该都是这些相对比较耗时的task.

也就是说,对于其他task来说,除了enqueue/dequeue和queue work load的影响之外.
还收到来自未来的运行时的不预期的一些开销因素.

所以相对来说,LIFO的不确定性比较高.

另外一点就是对于原生Future这类从设计一开始就没有考虑callback的wrap方式.

guava的actor暴露的是一个ListenInPool的选择.
也就是扔到一个你提供的线程池里blocking get,然后再回调.

在实现的时候开始也采用了类似的做法.
类似Promise.costly就是在一个cache thread pool.
而对应的Promise.light才是在一个forkjoin pool里.

一个不太好的情况就是类似之前go的syscall造成的大量thread的问题.

把future listen在一个cache thread pool的问题就是可能某个瞬间产生大量future的话,会意外地尝试非常多的thread.

当然,一个思路就是限制thread数量.
但是引入cache pool的原因就是想避免一些意外bug或者intended的不会返回的future耗尽thread的问题.

折中的办法是先把future queue起来.
然后类似早期go的net poller,定期的poll遍历touch一下.

代价就是有额外的这个poll的delay.

另外一个模仿点就是timeout.
基本上就是select timeout channel的future形式.
scheudle一个delay的future cancle.

可能本质上来说,就是在各种模仿.

毕竟人类.

相关文章

  • 毕竟人类

    考虑一种调用风格. Promise.costly(()- >receive()).transform((packe...

  • 人类毕竟是利益的动

    【珍信励行•如华悟语836】即使在同一认知层次,何况你怎么就能认定对方和你同一认知层次?你总不能自以为是,即使对方...

  • 毕竟白嫖,才是人类的本质

    最近我在测试一个项目,那就是看我平时发的两篇文章,开启付费和不付费的效果如何,经过几天的测试,我发现开启付费以...

  • 毕竟

    忒呢啊

  • 毕竟

    谢谢你的微笑,曾经慌乱过我的年华。

  • 毕竟

    毕竟鸟儿会飞走 从这个地方 飞到谁那里 毕竟 它长大了 想飞去远方 毕竟 谁都不知道 它是否 就像从前那样 飞着 ...

  • 毕竟

    啊咯

  • 毕竟

    毕竟相识时因为爱 毕竟我曾爱过你 毕竟雾霾天后有晴天 毕竟大寒后有太阳 毕竟人间自有温情在 何必只盯着一望无垠的冰...

  • 毕竟

    这词做不了作文,造个句算了。 ~毕竟老了,太大的想法不现实。 ~毕竟过了那么多年,这点仇就忘了算了。 ~他毕竟是你...

  • 毕竟。

    想送给你的花在行李中乱成了一把,我没有想过它经不住我旅途中的磨搓。那是玫瑰也可能会是曼陀罗。 是属于爱情亦或是曾经...

网友评论

      本文标题:毕竟人类

      本文链接:https://www.haomeiwen.com/subject/aifkdqtx.html