akka-stream是多线程non-blocking模式的,一般来说,运算任务提交到另外线程后这个线程就会在当前程序控制之外自由运行了。任何时候如果需要终止运行中的数据流就必须采用一种任务柄(handler)方式来控制在其它线程内运行的任务。这个handler可以在提交运算任务时获取。akka-stream提供了KillSwitch trait来支持这项功能:

  1. /**
  2. * A [[KillSwitch]] allows completion of [[Graph]]s from the outside by completing [[Graph]]s of [[FlowShape]] linked
  3. * to the switch. Depending on whether the [[KillSwitch]] is a [[UniqueKillSwitch]] or a [[SharedKillSwitch]] one or
  4. * multiple streams might be linked with the switch. For details see the documentation of the concrete subclasses of
  5. * this interface.
  6. */
  7. //#kill-switch
  8. trait KillSwitch {
  9. /**
  10. * After calling [[KillSwitch#shutdown()]] the linked [[Graph]]s of [[FlowShape]] are completed normally.
  11. */
  12. def shutdown(): Unit
  13. /**
  14. * After calling [[KillSwitch#abort()]] the linked [[Graph]]s of [[FlowShape]] are failed.
  15. */
  16. def abort(ex: Throwable): Unit
  17. }
  18. //#kill-switch

可以想象:我们必须把这个KillSwitch放在一个流图中间,所以它是一种FlowShape的,这可以从KillSwitch的构建器代码里可以看得到:

  1. object KillSwitches {
  2.  
  3. /**
  4. * Creates a new [[SharedKillSwitch]] with the given name that can be used to control the completion of multiple
  5. * streams from the outside simultaneously.
  6. *
  7. * @see SharedKillSwitch
  8. */
  9. def shared(name: String): SharedKillSwitch = new SharedKillSwitch(name)
  10.  
  11. /**
  12. * Creates a new [[Graph]] of [[FlowShape]] that materializes to an external switch that allows external completion
  13. * of that unique materialization. Different materializations result in different, independent switches.
  14. *
  15. * For a Bidi version see [[KillSwitch#singleBidi]]
  16. */
  17. def single[T]: Graph[FlowShape[T, T], UniqueKillSwitch] =
  18. UniqueKillSwitchStage.asInstanceOf[Graph[FlowShape[T, T], UniqueKillSwitch]]
  19.  
  20. /**
  21. * Creates a new [[Graph]] of [[FlowShape]] that materializes to an external switch that allows external completion
  22. * of that unique materialization. Different materializations result in different, independent switches.
  23. *
  24. * For a Flow version see [[KillSwitch#single]]
  25. */
  26. def singleBidi[T1, T2]: Graph[BidiShape[T1, T1, T2, T2], UniqueKillSwitch] =
  27. UniqueBidiKillSwitchStage.asInstanceOf[Graph[BidiShape[T1, T1, T2, T2], UniqueKillSwitch]]
  28. ...}

akka-stream提供了single,shared,singleBidi三种KillSwitch的构建方式,它们的形状都是FlowShape。KillSwitches.single返回结果类型是Graph[FlowShape[T,T],UniqueKillSwitch]。因为我们需要获取这个KillSwitch的控制柄,所以要用viaMat来可运算化(materialize)这个Graph,然后后选择右边的类型UniqueKillSwitch。这个类型可以控制一个可运算化FlowShape的Graph,如下:

  1. val source = Source(Stream.from(,)).delay(.second,DelayOverflowStrategy.backpressure)
  2. val sink = Sink.foreach(println)
  3. val killSwitch = source.viaMat(KillSwitches.single)(Keep.right).to(sink).run()
  4.  
  5. scala.io.StdIn.readLine()
  6. killSwitch.shutdown()
  7. println("terminated!")
  8. actorSys.terminate()

当然,也可以用异常方式中断运行:

  1. killSwitch.abort(new RuntimeException("boom!"))

source是一个不停顿每秒发出一个数字的数据源。如上所述:必须把KillSwitch放在source和sink中间形成数据流完整链状。运算这个数据流时返回了handle killSwitch,我们可以使用这个killSwitch来shutdown或abort数据流运算。

KillSwitches.shared构建了一个SharedKillSwitch类型。这个类型可以被用来控制多个FlowShape Graph的终止运算。SharedKillSwitch类型里的flow方法可以返回终止运算的控制柄handler:

  1. /**
  2. * Returns a typed Flow of a requested type that will be linked to this [[SharedKillSwitch]] instance. By invoking
  3. * [[SharedKillSwitch#shutdown()]] or [[SharedKillSwitch#abort()]] all running instances of all provided [[Graph]]s by this
  4. * switch will be stopped normally or failed.
  5. *
  6. * @tparam T Type of the elements the Flow will forward
  7. * @return A reusable [[Graph]] that is linked with the switch. The materialized value provided is this switch itself.
  8. */
  9. def flow[T]: Graph[FlowShape[T, T], SharedKillSwitch] = _flow.asInstanceOf[Graph[FlowShape[T, T], SharedKillSwitch]]

用flow构建的SharedKillSwitch实例就像immutable对象,我们可以在多个数据流中插入SharedKillSwitch,然后用这一个共享的handler去终止使用了这个SharedKillSwitch的数据流运算。下面是SharedKillSwitch的使用示范:

  1. val sharedKillSwitch = KillSwitches.shared("multi-ks")
  2. val source2 = Source(Stream.from()).delay(.second,DelayOverflowStrategy.backpressure)
  3.  
  4. source2.via(sharedKillSwitch.flow).to(sink).run()
  5. source.via(sharedKillSwitch.flow).to(sink).run()
  6.  
  7. scala.io.StdIn.readLine()
  8. killSwitch.shutdown()
  9. sharedKillSwitch.shutdown()

注意:我们先构建了一个SharedKillSwitch实例,然后在source2,source数据通道中间加入了这个实例。因为我们已经获取了sharedKillSwitch控制柄,所以不必理会返回结果,直接用via和to来连接上下游节点(默认为Keep.left)。

还有一个KillSwitches.singleBidi类型,这种KillSwitch是用来终止双流向数据流运算的。我们将在下篇讨论里介绍。

下面是本次示范的源代码:

  1. import akka.stream.scaladsl._
  2. import akka.stream._
  3. import akka.actor._
  4. import scala.concurrent.duration._
  5. object KillSwitchDemo extends App {
  6. implicit val actorSys = ActorSystem("sys")
  7. implicit val ec = actorSys.dispatcher
  8. implicit val mat = ActorMaterializer(
  9. ActorMaterializerSettings(actorSys)
  10. .withInputBuffer(,)
  11. )
  12.  
  13. val source = Source(Stream.from(,)).delay(.second,DelayOverflowStrategy.backpressure)
  14. val sink = Sink.foreach(println)
  15. val killSwitch = source.viaMat(KillSwitches.single)(Keep.right).to(sink).run()
  16.  
  17. val sharedKillSwitch = KillSwitches.shared("multi-ks")
  18. val source2 = Source(Stream.from()).delay(.second,DelayOverflowStrategy.backpressure)
  19.  
  20. source2.via(sharedKillSwitch.flow).to(sink).run()
  21. source.via(sharedKillSwitch.flow).to(sink).run()
  22.  
  23. scala.io.StdIn.readLine()
  24. killSwitch.shutdown()
  25. sharedKillSwitch.shutdown()
  26. println("terminated!")
  27. actorSys.terminate()
  28.  
  29. }

Akka(21): Stream:实时操控:人为中断-KillSwitch的更多相关文章

  1. 【STM32H7教程】第21章 STM32H7的NVIC中断分组和配置(重要)

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第21章       STM32H7的NVIC中断分组和配置( ...

  2. Akka(22): Stream:实时操控:动态管道连接-MergeHub,BroadcastHub and PartitionHub

    在现实中我们会经常遇到这样的场景:有一个固定的数据源Source,我们希望按照程序运行状态来接驳任意数量的下游接收方subscriber.又或者我需要在程序运行时(runtime)把多个数据流向某个固 ...

  3. 记一个实时Linux的中断线程化问题

    背景 有一个项目对实时性要求比较高,于是在linux内核上打了RT_PREEMPT补丁. 最终碰到的一个问题是,芯片本身性能不强,CPU资源不足,急需优化. 初步分析 看了下cpu占用率,除了主应用之 ...

  4. 【RL-TCPnet网络教程】第21章 RL-TCPnet之高效的事件触发框架

    第21章       RL-TCPnet之高效的事件触发框架 本章节为大家讲解高效的事件触发框架实现方法,BSD Socket编程和后面章节要讲解到的FTP.TFTP和HTTP等都非常适合使用这种方式 ...

  5. [IC]浅谈嵌入式MCU软件开发之中断优先级与中断嵌套

    转自:https://mp.weixin.qq.com/s?__biz=MzI0MDk0ODcxMw==&mid=2247483680&idx=1&sn=c5fd069ab3f ...

  6. 文件转移 互联网组成 路由器 分组交换 交换机 冲突域 网卡 数据帧的发送与接收会带来CPU开销 CPU中断 双网卡切换

    https://zh.wikipedia.org/zh-cn/网段 在以太网环境中,一个网段其实也就是一个冲突域(碰撞域).同一网段中的设备共享(包括通过集线器等设备中转连接)同一物理总线,在这一总线 ...

  7. ASM:《X86汇编语言-从实模式到保护模式》第17章:保护模式下中断和异常的处理与抢占式多任务

    ★PART1:中断和异常概述 1. 中断(Interrupt) 中断包括硬件中断和软中断.硬件中断是由外围设备发出的中断信号引发的,以请求处理器提供服务.当I/O接口发出中断请求的时候,会被像8259 ...

  8. s5pv210中断体系

    一.什么是中断? 1.中断的发明是用来解决宏观上的并行需要的.宏观就是从整体上来看,并行就是多件事情都完成了. 2.微观上的并行,就是指的真正的并行,就是精确到每一秒甚至每一刻,多个事情都是在同时进行 ...

  9. CUDA ---- Stream and Event

    Stream 一般来说,cuda c并行性表现在下面两个层面上: Kernel level Grid level 到目前为止,我们讨论的一直是kernel level的,也就是一个kernel或者一个 ...

随机推荐

  1. jmeter连接配置带跳板机(SSH)的mysql服务器

    jmeter连接配置mysql服务器时,如果数据库服务器没有通过ssh连接,则只需要配置相应的jdbc参数就可以了,即请求域名或ip地址:3306,如果数据库服务器是通过SSH连接的,那需要通过中间远 ...

  2. pyqt5 在qt designer后以弹窗的方式连接多个UI图形界面

    当我们通过pyqt开发时,eric6为我们提供了一个方便的工具:图形化的绘制UI工具--qt designer. 我们可以通过它开发多个UI,然后利用信号-槽工具,将功能代码附着在上面.也可以将多个界 ...

  3. HDOJ2007-平方和与立方和

    Problem Description 给定一段连续的整数,求出他们中所有偶数的平方和以及所有奇数的立方和.   Input 输入数据包含多组测试实例,每组测试实例包含一行,由两个整数m和n组成.   ...

  4. Angularjs跳转切换至对应选项卡

    //跳转前页面 <div class="list user_order" ng-click="userOpen('userOrder',0)"> & ...

  5. Vivado完成综合_实现_生成比特流后发出提醒声音-原创☺

    之前做技术支持时,有过客户吐槽Vivado运行时间长,又不能在完成工作后发送提醒,这两天又有人提起,所以决定写篇帖子. 大家知道,Vivado的技术文档总提及tcl,不过似乎很不招人待见,很少有人研究 ...

  6. node调用phantomjs-node爬取复杂页面

    什么是phantomjs phantomjs官网是这么说的,'整站测试,屏幕捕获,自动翻页,网络监控',目前比较流行用来爬取复杂的,难以通过api或正则匹配的页面,比如页面是通过异步加载.phanto ...

  7. Linux(2)文件和权限

    用户目录 位于/home/user, 称为用户目录或家目录, 表示方法: /home/user ~ 相对路径和绝对路径 绝对路径 从 / 目录开始描述的路径外绝对路径 cd /home cd /usr ...

  8. 双向循环链表(C语言描述)(二)

    链表的基本操作基于对链表的遍历:计算链表的长度就是对链表进行一次遍历: int linkedlist_length(const LinkedList list) { assert(list); ; L ...

  9. Java中synchronized和Lock的区别

    synchronized和Lock的区别synchronize锁对象可以是任意对象,由于监视器方法必须要拥有锁对象那么任意对象都可以调用的方法所以将其抽取到Object类中去定义监视器方法这样锁对象和 ...

  10. Vmware虚拟机安装win7系统教程

    第一步:下载虚拟机 可以下载VMware虚拟机,这里用的是Vmware12专业版,百度网盘直通车密码:c3mt密钥:5A02H-AU243-TZJ49-GTC7K-3C61N 第二部:安装 第三部:做 ...