使用Scala实现一个并发库(阻塞版本, 下一篇文章提供NonBlocking版本)

Spark读取ES数据之Scala版 使用Spark读取ES数据 因为工作需要,所以针对性学习了一波ES查询,并总结了一波 阅读详情

这个例子来源于scala圣经级教程《Functional Programming in Scala》,由于本人跟着书中的代码敲了一遍,然后写了点测试代码验证了一下正确性,所以就放在这做个备忘吧。贴出来只是为了方便自己,如果看不懂,但是又感兴趣的就去看原书吧……

> 注:这个并发库使用的线程池如果只有唯一一条工作线程的话,会导致线程阻塞,可以参考main方法中的示例,阻塞原因与代码中fork的实现细节有关,所以,本人会在下一篇文章提供一个非阻塞的版本…..

package parallelism

import java.util.concurrent._

object Par {

  type Par[A] = ExecutorService => Future[A]

  def run[A](s: ExecutorService)(a: Par[A]): Future[A] = a(s)

  /**
    * `unit` is represented as a function that returns a `UnitFuture`,
    * which is a simple implementation of `Future` that just wraps a constant value.
    * It doesn't use the `ExecutorService` at all. It's always done and can't be cancelled.
    * Its `get` method simply returns the value that we gave it.
    */
  def unit[A](a: A): Par[A] = (es: ExecutorService) => UnitFuture(a)

  private case class UnitFuture[A](get: A) extends Future[A] {

    override def cancel(mayInterruptIfRunning: Boolean) = false

    override def isCancelled = false

    override def isDone = true

    override def get(timeout: Long, unit: TimeUnit) = get
  }

  /**
    * `map2` doesn't evaluate the call to `f` in a separate logical thread,
    * in accord with our design choice of having `fork` be the sole function in the API for controlling parallelism.
    * We can always do `fork(map2(a,b)(f))` if we want the evaluation of `f` to occur in a separate thread.
    */
  def map2[A, B, C](a: Par[A], b: Par[B])(f: (A, B) => C): Par[C] = (es: ExecutorService) => {
    val af = a(es)
    val bf = b(es)
    // This implementation of `map2` does _not_ respect timeouts.
    // It simply passes the `ExecutorService` on to both `Par` values,
    // waits for the results of the Futures `af` and `bf`,
    // applies `f` to them, and wraps them in a `UnitFuture`.
    // In order to respect timeouts, we'd need a new `Future` implementation that records the amount of time spent evaluating `af`,
    // then subtracts that time from the available time allocated for evaluating `bf`.
    UnitFuture(f(af.get, bf.get))
  }

  /**
    * This is the simplest and most natural implementation of `fork`,
    * but there are some problems with it--for one, the outer `Callable` will block waiting for the "inner" task to complete.
    * Since this blocking occupies a thread in our thread pool, or whatever resource backs the `ExecutorService`,
    * this implies that we're losing out on some potential parallelism. Essentially, we're using two threads when one should suffice.
    * This is a symptom of a more serious problem with the implementation, and we will discuss this later in the chapter.
    */
  def fork[A](a: => Par[A]): Par[A] = es => es.submit(
    new Callable[A] {
      override def call() = a(es).get
    })

  def lazyUnit[A](a: => A): Par[A] = fork(unit(a))

  def asyncF[A, B](f: A => B): A => Par[B] = a => lazyUnit(f(a))

  def map[A, B](pa: Par[A])(f: A => B): Par[B] = map2(pa, unit(()))((a, _) => f(a))

  def sortPar(parList: Par[List[Int]]) = map(parList)(_.sorted)

  def sequence_simple[A](l: List[Par[A]]): Par[List[A]] = l.foldRight[Par[List[A]]](unit(List[A]()))((h, t) => map2(h, t)(_ :: _))

  /**
    * This implementation forks the recursive step off to a new logical thread,
    * making it effectively tail-recursive. However, we are constructing
    * a right-nested parallel program, and we can get better performance by
    * dividing the list in half, and running both halves in parallel.
    * See `sequenceBalanced` below.*/
  def sequenceRight[A](as: List[Par[A]]): Par[List[A]] = as match {
    case Nil => unit(Nil)
    case h :: t => map2(h, fork(sequenceRight(t)))(_ :: _)
  }

  /**
    * We define `sequenceBalanced` using `IndexedSeq`, which provides an
    * efficient function for splitting the sequence in half.*/
  def sequenceBalanced[A](as: IndexedSeq[Par[A]]): Par[IndexedSeq[A]] = fork {
    if (as.isEmpty) unit(Vector())
    else if (as.length == 1) map(as.head)(a => Vector(a))
    else {
      val (l, r) = as.splitAt(as.length / 2)
      map2(sequenceBalanced(l), sequenceBalanced(r))(_ ++ _)
    }
  }

  def sequence[A](as: List[Par[A]]): Par[List[A]] = map(sequenceBalanced(as.toIndexedSeq))(_.toList)

  def parFilter[A](l: List[A])(f: A => Boolean): Par[List[A]] = {
    val pars: List[Par[List[A]]] = l map (asyncF((a: A) => if (f(a)) List(a) else List()))
    map(sequence(pars))(_.flatten)
  }

  def equal[A](e: ExecutorService)(p: Par[A], p2: Par[A]): Boolean = p(e).get == p2(e).get

  def delay[A](fa: => Par[A]): Par[A] = es => fa(es)

  // Notice we are blocking on the result of `cond`.
  def choice[A](cond: Par[Boolean])(t: Par[A], f: Par[A]): Par[A] = es => if (run(es)(cond).get) t(es) else f(es)

  def choiceN[A](n: Par[Int])(choices: List[Par[A]]): Par[A] =
    es => {
      // Full source files
      val ind = run(es)(n).get
      run(es)(choices(ind))
    }

  def choiceViaChoiceN[A](a: Par[Boolean])(ifTrue: Par[A])(ifFalse: Par[A]): Par[A] = choiceN(map(a)(b => if (b) 0 else 1))(List(ifTrue, ifFalse))

  def choiceMap[K, V](key: Par[K])(choices: Map[K, Par[V]]): Par[V] =
    es => {
      val kVal = run(es)(key).get
      run(es)(choices(kVal))
    }

  def chooser[A, B](p: Par[A])(choices: A => Par[B]): Par[B] =
    es => {
      val k = run(es)(p).get
      run(es)(choices(k))
    }

  /** `chooser` is usually called `flatMap` or `bind`.
    * and you will find, flatMap is a higher abstract for chooser/choiceMap/choice/choiceN
    */
  def flatMap[A, B](p: Par[A])(choices: A => Par[B]): Par[B] =
    es => {
      val k = run(es)(p).get
      run(es)(choices(k))
    }

  def choiceViaFlatMap[A](p: Par[Boolean])(f: Par[A], t: Par[A]): Par[A] = flatMap(p)(b => if (b) f else t)

  def choiceNViaFlatMap[A](p: Par[Int])(choices: List[Par[A]]): Par[A] = flatMap(p)(i => choices(i))

  def joinViaFlatMap[A](pp: Par[Par[A]]): Par[A] = flatMap(pp)(p => p)

  def join[A](a: Par[Par[A]]): Par[A] = es => run(es)(run(es)(a).get())

  def flatMapViaJoin[A, B](p: Par[A])(f: A => Par[B]): Par[B] = join(map(p)(f))

  /* Gives us infix syntax for `Par`. */
  implicit def toParOps[A](p: Par[A]): ParOps[A] = new ParOps(p)

  class ParOps[A](p: Par[A]) {}

}

object Examples {

  import Par._

  def sum(ints: IndexedSeq[Int]): Int =
    if (ints.size <= 1) ints.headOption getOrElse 0 else {
      val (l, r) = ints.splitAt(ints.length / 2)
      sum(l) + sum(r)
    }

  def main(args: Array[String]): Unit = {

    println(sum(Range(0, 10)))

    val es = Executors.newFixedThreadPool(2)

    val parInt: Par[Int] = es => es.submit(new Callable[Int] {
      override def call() = ((System.currentTimeMillis + 1.0) / System.currentTimeMillis)   toInt
    })

    val parString: Par[String] = es => es.submit(new Callable[String] {
      override def call() = " |<*>| " * 3
    })

    val parIntMap = Par.map(parInt)((a: Int) => a * 8)

    val parMap2 = Par.map2[Int, String, (Int, String)](parInt, parString)((_ -> _))

    println(run(es)(parInt).get)

    println(run(es)(parIntMap).get)


    println(run(es)(parMap2).get)


    //  will lead to deadLock because the number of thread  is 1 in thread pool `es`
    println(run(es)(fork(parMap2)).get)

    es shutdown


    val singleThreadEs = Executors.newFixedThreadPool(1) // fork Par[A] will lead to block
//    val singleThreadEs = Executors.newFixedThreadPool(2) // fork Par[A] will not lead to block

    // singleThreadEs如果只有一条线程,则会发生阻赛, 不能println结果
    //如果singleThreadEs只有唯一一条工作线程, 那么控制台看不到结果,
    println(run(singleThreadEs)(fork(parMap2)).get)
    singleThreadEs shutdown //如果上一行代码阻赛,shutdown 方法永远不会被调用
  }
}

上述代码的运行结果是:

45
1
8
(1, |<*>|  |<*>|  |<*>| )
(1, |<*>|  |<*>|  |<*>| )
879675643@qq.com  lhever

.---.                                                                         
|   |   .              __.....__   .----.     .----.   __.....__              
|   | .'|          .-''         '.  \    \   /    /.-''         '.            
|   |<  |         /     .-''"'-.  `. '   '. /'   //     .-''"'-.  `. .-,.--.  
|   | | |        /     /________\   \|    |'    //     /________\   \|  .-. | 
|   | | | .'''-. |                  ||    ||    ||                  || |  | | 
|   | | |/.'''. \\    .-------------''.   `'   .'\    .-------------'| |  | | 
|   | |  /    | | \    '-.____...---. \        /  \    '-.____...---.| |  '-  
|   | | |     | |  `.             .'   \      /    `.             .' | |      
'---' | |     | |    `''-...... -'      '----'       `''-...... -'   | |      
      | '.    | '.                                                   |_|      
      '---'   '---'  
U盘无法识别故障排查与数据恢复实战指南 USB存储设备(如U盘、移动硬盘)与计算机系统间的通信依赖于一套标准的枚举、驱动加载和协议握手流程。当设备插入后出现‘无法识别’提示,通常意味着这一通信链路在供电、驱动、文件系统或硬件层面的某个环节中断。理解其底层原理,对于数据恢复和硬件维护具有重要价值。本文聚焦于此类常见故障,通过系统化的排查方法,从基础的物理连接、驱动重置,到深入的系统策略调整,最终延伸至使用专业工具进行芯片级检测与底层数据恢复。其中,数据恢复和量产工具是应对固件损坏或文件系统严重错误的关键技术手段,旨在帮助用户重建访问路径,安全取回存 阅读详情

相关推荐

开源Agent Skill让AI画图不再翻车:从数据到专业图表全流程

在人工智能与数据可视化交叉领域,让模型直接生成图表往往伴随字体乱码、坐标轴密集、配色失调等高频问题。Agent Skill作为一种可复用的能力封装机制,将专业绘图流程固化为标准化操作手册,从数据特征识别、图表类型决策到代码生成与渲染校验形成完整闭环。它不再依赖临时提示词的一次性发挥,而是让AI按领域专家的思维执行任务,显著提升出图质量与稳定性。这种能力在数据分析报告、运营日报、论文插图等场景具有广泛实用价值,尤其适用于需要快速产出规范化图表的工作流。本文即从这一技术范式出发,介绍一个GitHub上获得2.5

weixin_33851429的博客 998

Scala 异步编程之 Future

同步异步,阻塞非阻塞,在IO模型中几个概念组合在一起不是很容易理解,但是只从代码执行的角度看同步异步是很清晰的: 同步代表这段代码中的逻辑必须执行完毕,而异步代表调用马上返回,但通常情况下是获取不到需要的值。 同步:val  value={ Thread.sleep(2000) 1 } 异步: val value=Future{ Thread.sleep(2000) 1 }

onwingsofsong的博客 8483

PTrade数据交互全流程详解:从本地文件上传到定时导出交易数据

本文详细解析了PTrade量化交易平台的数据交互全流程,涵盖从本地文件自动上传交易指令到定时导出成交数据的完整链路。通过文件媒介实现本地策略与云端实盘的安全、稳定对接,并提供了构建自动化、稳健数据流水线的实战配置方案与代码示例,助力量化工作流平滑过渡至实盘。

gg901的博客 884

Scala 队列

队列是一个有序列表,在底层可以用数组或是链表来实现 其输入和输出要遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出。 在Scala中,由设计者直接给我们提供队列类型使用。 在Scala中,有 scala.collection.mutable.Queue 和 scala.collection.immutable.Queue ,一般来说我们在开发中通常使用可变集合中的队列 ...

Simple 专栏 1958

数学建模——相关系数(4)——斯皮尔曼相关系数(spearman)

文章目录引述斯皮尔曼相关系数(spearman)定义 引述 经过之前几节的学习,我们了解并掌握了皮尔逊相关系数。在学习中我们发现,皮尔逊相关系数的使用条件相当苛刻:两组变量必须是连续数据、呈现正态分布,且两者间必须成线性关系。如果我们在数学建模中拿到一组数据无法满足以上条件,那么有没有其他的方法去判断两组变量之间的相关性呢?答案是肯定的,它就是斯皮尔曼相关系数(spearman). 斯皮尔曼相关系...

东 6万+

WindTerm 安装使用教程

WindTerm是一款Github上开源的 SSH 终端工具,它是完全可以比肩MobaXterm工具的。

m0_69576880的博客 4038

Scala多线程:使用线程池Executors提交Runnable任务代码示例

运行结果:

学亮编程手记 1677

uni-app - 最详细 H5 网页接入微信登录功能,提供公众号配置与详细注释示例代码(移动端网页实现点击登录按钮后 调用微信公众号授权登录功能 详细讲解接入流程与详细示例代码)官方最新超级详细教程

uniapp中H5微信登录,uniapp H5微信授权登录,微信公众号第三方网页(H5)授权登录(OAuth2.0)流程及逻辑详细教程,UNIAPP 开发H5 怎么实现微信公众号登录功能,uniapp如何实现H5网页的公众号微信登录,怎么做uniapp微信登录,uniapp h5项目怎么实现微信登录的功能,uniapp微信浏览器H5授权微信登录,UniApp开发H5接入微信登录的全过程,uniapp的H5页面使用微信登录,uniapp H5微信授权登录,H5之微信授权登陆 (uniapp网页版微信授权登录)

🏆 前端领域优质创作者 7410

scala 多线程_Scala中的多线程

scala 多线程 Scala多线程 (Scala Multithreading) Multithreading is the concept of using multiple threads simultaneously that allows the program to perform multiple operations simultaneously. 多线程是同时使用多个线程的概...

cumt951045的博客 2121

自适应滤波-----LMS(Least Mean Square)算法

自适应滤波的意义所在 自适应滤波器解决非平稳的过程,因为实际信号的统计特性可能是非平稳的或者是未知的。 自适应滤波器的特点: 1.没有关于待提取信息的先验统计知识 2.直接利用观测数据依据某种判据在观测过程中不断递归更新 3.最优化 自适应滤波分类: 处理器的结构划分:横向结构、格型结构 重复一次计算自适应需要的数据划分:成批处理法、递归处理法 按调节算法...

heda3的博客 10万+

【DRAM存储器五十一】LPDDR5介绍--DFE与Pre-Emphasis

简述LPDDR5的DFE和预加重应用设置

highman110的博客 711

使用Scala实现一个并发库(NonBlocking版本)

这个例子来源于scala圣经级教程《Functional Programming in Scala》,由于本人跟着书中的代码敲了一遍,然后写了点测试代码验证了一下正确性,所以就放在这做个备忘吧。贴出来只是为了方便自己,如果看不懂,但是又感兴趣的就去看原书吧…… &gt; 注:本文是上一篇文章《使用Scala实现一个并发库(阻塞版本, 下一篇文章提供NonBlocking版本)》的延续...

lhever_的博客 345

手把手教你学Simulink--控制策略与算法的DC-DC变换器领域仿真领域建模实例:基于Simulink实现一个双闭环控制Buck变换器的仿真建模

目录主要步骤1. 前期准备2. 构建Buck变换器模型3. 定义双闭环控制器4. 设置参考电压和反馈回路5. 实现双闭环控制器逻辑6. 仿真参数设置7. 运行仿真与结果分析示例整合代码片段1. Simulink模型2. 双闭环控制器参数调节3. 仿真结果分析总结双闭环控制是一种常见的控制策略,广泛应用于电力电子系统(如DC-DC变换器)中。它通过内外两个环路的协同工作,分别控制系统的动态性能和稳态性能。对于Buck变换器,通常采用电流内环和电压外环的双闭环控制结构。以下是一个手把手教程,帮助你基于Simul

MHD0815的博客 327

Scala中使用Future进行并发处理

有时候将一些执行时间长并且难以被中断的任务使用Future并发处理确实能够提高效率

基因记忆 5420

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

scala 异步调用_非阻塞异步Java 8和Scala的Try / Success / Failure

scala 异步调用 受Heinz Kabutz最近的时事通讯以及我在最近的书中研究的Scala的期货的启发,我着手使用Java 8编写了一个示例,该示例如何将工作提交给执行服务并异步地响应其结果,并使用了回调。无需阻止任何线程等待执行服务的结果。 理论认为,调用拦截方法,如get上java.util.concurrent.Future是坏的,因为系统会需要超过线程的最佳数量,如果它是不断...

最佳 Java 编程 472

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

socke通信之三:阻塞版本的客户/服务器模型

上一篇中实现出来的客户端只能向服务器端发送一次数据,然后就断开了连接,那么如果需要向服务器端持续发送数据,那么应该怎么做? 一个很直观地想法就是修改客户端的第4步,即发送,接收数据那一步,在基本的客户/服务器模型中我们是直接发送一个字符串给服务器端,现在我们从控制台接收数据将接收到的数据发送给服务器端,然后从服务端端接收数据并打印输出。并持续从控制台读取数据。

1226

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Scala 并发编程

Scala 并发编程 Runnable/Callable Runnable 接口只有一个没有返回值的方法。 trait Runnable { def run(): Unit } Callable与之类似,除了它有一个返回值 trait Callable[V] { def call(): V } 线程 Scala 并发是建立在 Java 并发模型基础上的。

赵英超的博客 1514

同时使用java和scala语言的maven项目pom文件示例

主要就是在pom.xml中添加scala的三个依赖包和maven-scala插件,配置如下:&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-in...

lhever_的博客 3157

使用Scala实现链表(List)数据结构

这个例子来源于scala圣经级教程《Functional Programming in Scala》,由于本人跟着书中的代码敲了一遍,然后写了点测试代码验证了一下正确性,所以就放在这做个备忘吧。贴出来只是为了方便自己,如果看不懂,但是又感兴趣的就去看原书吧。package fpinscala.datastructures sealed trait List[+A] case object Nil...

lhever_的博客 1877

Monoid在Scala中的应用笔记

这个例子来源于scala圣经级教程《Functional Programming in Scala》,虽然原书的随书代码可以找到这些类的影子,但却没有关于如何使用这些类的示例代码,本人在阅读此书期间,除了跟着书中的代码敲了一遍之外,还写了一些测试代码进行验证,贴出来作为blog主要是为了方便自己,也为那些同样在阅读此书的人参考。注释不多,本人也不可能写太多,因为这本书不是简单的入门书,而是...

lhever_的博客 1404

Monad在Scala中的应用笔记

这个例子来源于scala圣经级教程《Functional Programming in Scala》,虽然原书的随书代码可以找到这些类的影子,但却没有关于如何使用这些类的示例代码,本人在阅读此书期间,除了跟着书中的代码敲了一遍之外,还写了一些测试代码进行验证,贴出来作为blog主要是为了方便自己,也为那些同样在阅读此书的人参考。注释不多,本人也不可能写太多,因为这本书不是简单的入门书,而是...

lhever_的博客 1310

使用Scala从头实现一个简单的语法分析器组合字库

这个例子来源于scala圣经级教程《Functional Programming in Scala》,虽然原书的随书代码可以找到这些类的影子,但却没有关于如何使用这些类的示例代码,本人在阅读此书期间, ,除了跟着书中的代码敲了一遍之外,还写了一些测试代码进行验证,贴出来作为blog主要是为了方便自己,也为那些同样在阅读此书的人参考。注释不多,本人也不可能写太多,因为这本书不是简单的入门书,...

lhever_的博客 1002

用Scala实现Stream(一个惰性的链表)数据结构

这个例子来源于scala圣经级教程《Functional Programming in Scala》,由于本人跟着书中的代码敲了一遍,然后写了点测试代码验证了一下正确性,所以就放在这做个备忘吧。贴出来只是为了方便自己得意,如果看不懂,但是又感兴趣的就去看原书吧…… package laziness trait Stream[+A] { import laziness.Stream...

lhever_的博客 995

使用Scala对带状态函数或API进行抽象的示例(State)

这个例子来源于scala圣经级教程《Functional Programming in Scala》,由于本人跟着书中的代码敲了一遍,然后写了点测试代码验证了一下正确性,所以就放在这做个备忘吧。贴出来只是为了方便自己,如果看不懂,但是又感兴趣的就去看原书吧…… package state import RNG.Simple import state.State._ case cla...

lhever_的博客 659

使用Scala实现Option数据结构

这个例子来源于scala圣经级教程《Functional Programming in Scala》,由于本人跟着书中的代码敲了一遍,然后写了点测试代码验证了一下正确性,所以就放在这做个备忘吧。贴出来只是为了方便自己,如果看不懂,但是又感兴趣的就去看原书吧。package errorhandling //hide std library `Option`, since we are writing...

lhever_的博客 606

用Scala实现一个纯函数风格的引用透明的伪随机数生成器

这个例子来源于scala圣经级教程《Functional Programming in Scala》,由于本人跟着书中的代码敲了一遍,然后写了点测试代码验证了一下正确性,所以就放在这做个备忘吧。贴出来只是为了方便自己,如果看不懂,但是又感兴趣的就去看原书吧…… package state trait RNG { def nextInt: (Int, RNG) } obje...

lhever_的博客 567
上一篇: 使用Scala对带状态函数或API进行抽象的示例(State)
下一篇: 使用Scala实现一个并发库(NonBlocking版本)
lhever_
博客等级 码龄14年 213粉丝 130原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值