Chisel教程——04.Chisel中的控制流

2023-11-04

控制流

动机

本系列到目前为止,Chisel中的软硬件之间都有很强的对应关系。但引入控制流之后就不一样了,对软硬件的看法就应该有很大的分歧了。

本节会在生成器软件和硬件中都引入控制流。如果重新连接到一个Chisel连线会怎么样呢?如何让一个多路选择器有两个以上的输入呢?本节会给出这两个问题的答案。

最后连接语义

前面提到,Chisel通过运算符:=来连接组件,由于各种原因,允许发射多条连接语句到相同的组件。

对于赋值之后重新赋值的多条语句,最后一条连接语句会生效:

class LastConnect extends Module {
  val io = IO(new Bundle {
    val in = Input(UInt(4.W))
    val out = Output(UInt(4.W))
  })
  io.out := 1.U
  io.out := 2.U
  io.out := 3.U
  io.out := 4.U
}

//  Test LastConnect
test(new LastConnect) { c => c.io.out.expect(4.U) } // Assert that the output correctly has 4
println("SUCCESS!!") // Scala Code: if we get here, our tests passed!

whenelsewhenotherwise

Chisel中主要的条件逻辑实现是whenelsewhenotherwise结构,一般看起来是这样的:

when(someBooleanCondition) {
  // things to do when true
}.elsewhen(someOtherBooleanCondition) {
  // things to do on this condition
}.otherwise {
  // things to do if none of th boolean conditions are true
}

他们仨必须按照上面的顺序出现,后面的可以省略,可以出现任意多的elsewhen子句。

任何为真的子句条件都会终止执行,子句执行的动作可以是复杂的语句块或者嵌套的when

与Scala中的if不同的是,when中的子句不会返回值。所以不能这么用:

val result = when(squareIt) { x * x}.otherwise {x}

解决方案会在后面的连线(Wire)小节提到。

下面是一个用when构造Chisel条件语句的例子:

import chisel3._
import chisel3.util._

class Max3 extends Module {
  val io = IO(new Bundle {
    val in_a = Input(UInt(16.W))
    val in_b = Input(UInt(16.W))
    val in_c = Input(UInt(16.W))
    val out  = Output(UInt(16.W))
  })

  when(io.in_a >= io.in_b && io.in_a >= io.in_c) {
    io.out := io.in_a
  }.elsewhen(io.in_b >= io.in_c) {
    io.out := io.in_b
  }.otherwise {
    io.out := io.in_c
  }
}

object Max3 extends App {
  println(getVerilogString(new Max3()))
}

输出为:

module Max3(
  input         clock,
  input         reset,
  input  [15:0] io_in_a,
  input  [15:0] io_in_b,
  input  [15:0] io_in_c,
  output [15:0] io_out
);
  wire [15:0] _GEN_0 = io_in_b >= io_in_c ? io_in_b : io_in_c; // @[MyModule.scala 14:34 15:12 17:12]
  assign io_out = io_in_a >= io_in_b & io_in_a >= io_in_c ? io_in_a : _GEN_0; // @[MyModule.scala 12:50 13:12]
endmodule

测试部分:

import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec

class MyModuleTest extends AnyFlatSpec with ChiselScalatestTester {
  behavior of "MyOperators"
  it should "get right results" in {
    test(new Max3) { c =>
      // verify that the max of the three inputs is correct
      c.io.in_a.poke(6.U)
      c.io.in_b.poke(4.U)
      c.io.in_c.poke(2.U)
      c.io.out.expect(6.U)  // input 1 should be biggest
      c.io.in_b.poke(7.U)
      c.io.out.expect(7.U)  // now input 2 is
      c.io.in_c.poke(11.U)
      c.io.out.expect(11.U) // and now input 3
      c.io.in_c.poke(3.U)
      c.io.out.expect(7.U)  // show that decreasing an input works as well
      c.io.in_a.poke(9.U)
      c.io.in_b.poke(9.U)
      c.io.in_c.poke(6.U)
      c.io.out.expect(9.U)  // still get max with tie
    }

    println("SUCCESS!!") // Scala Code: if we get here, our tests passed!
  }
}

测试通过。

Wire结构

前面提到when不能返回值,Chisel中的Wire结构就是解决这个问题的方法之一。Wire定义了一个电路组件,他可以出现在:=操作符的左边或右边。

下面以一个四输入的使用Wire的排序电路为例:

为了演示,首先设计一个小的组合排序器,接受四个数值输入得到四个数值输出,考虑下面的图:

在这里插入图片描述

其中红色的线表示左边的值比右边的小,直接复制值就行,黑色的线表示左边的值比右边的值大时交换两个的值。

图中展示了一系列以row开头的格子,可以使用wire来构造这些格子,作为存放复制或交换的值的地方。

下面是代码实现,目前比较冗长,后面会有缩减的方法:

import chisel3._
import chisel3.util._

class Sort4 extends Module {
  val io = IO(new Bundle {
    val in0 = Input(UInt(16.W))
    val in1 = Input(UInt(16.W))
    val in2 = Input(UInt(16.W))
    val in3 = Input(UInt(16.W))
    val out0 = Output(UInt(16.W))
    val out1 = Output(UInt(16.W))
    val out2 = Output(UInt(16.W))
    val out3 = Output(UInt(16.W))
  })

  val row10 = Wire(UInt(16.W))
  val row11 = Wire(UInt(16.W))
  val row12 = Wire(UInt(16.W))
  val row13 = Wire(UInt(16.W))

  when(io.in0 < io.in1) {
    row10 := io.in0
    row11 := io.in1
  }.otherwise {
    row10 := io.in1
    row11 := io.in0
  }

  when(io.in2 < io.in3 ) {
    row12 := io.in2
    row13 := io.in3
  }.otherwise {
    row12 := io.in3
    row13 := io.in2
  }

  val row20 = Wire(UInt(16.W))
  val row21 = Wire(UInt(16.W))
  val row22 = Wire(UInt(16.W))
  val row23 = Wire(UInt(16.W))

  when(row10 < row13) {
    row20 := row10
    row23 := row13
  }.otherwise {
    row20 := row13
    row23 := row10
  }

  when(row11 < row12) {
    row21 := row11
    row22 := row12
  }.otherwise {
    row21 := row12
    row22 := row11
  }

  when(row20 < row21) {
    io.out0 := row20
    io.out1 := row21
  }.otherwise {
    io.out0 := row21
    io.out1 := row20
  }

  when(row22 < row23) {
    io.out2 := row22
    io.out3 := row23
  }.otherwise {
    io.out2 := row23
    io.out3 := row22
  }
}

object Sort4 extends App {
  println(getVerilogString(new Sort4()))
}

输出的Verilog代码如下:

module Sort4(
  input         clock,
  input         reset,
  input  [15:0] io_in0,
  input  [15:0] io_in1,
  input  [15:0] io_in2,
  input  [15:0] io_in3,
  output [15:0] io_out0,
  output [15:0] io_out1,
  output [15:0] io_out2,
  output [15:0] io_out3
);
  wire [15:0] row10 = io_in0 < io_in1 ? io_in0 : io_in1; // @[MyModule.scala 21:25 22:11 25:11]
  wire [15:0] row11 = io_in0 < io_in1 ? io_in1 : io_in0; // @[MyModule.scala 21:25 23:11 26:11]
  wire [15:0] row12 = io_in2 < io_in3 ? io_in2 : io_in3; // @[MyModule.scala 29:26 30:11 33:11]
  wire [15:0] row13 = io_in2 < io_in3 ? io_in3 : io_in2; // @[MyModule.scala 29:26 31:11 34:11]
  wire [15:0] row20 = row10 < row13 ? row10 : row13; // @[MyModule.scala 42:23 43:11 46:11]
  wire [15:0] row23 = row10 < row13 ? row13 : row10; // @[MyModule.scala 42:23 44:11 47:11]
  wire [15:0] row21 = row11 < row12 ? row11 : row12; // @[MyModule.scala 50:23 51:11 54:11]
  wire [15:0] row22 = row11 < row12 ? row12 : row11; // @[MyModule.scala 50:23 52:11 55:11]
  assign io_out0 = row20 < row21 ? row20 : row21; // @[MyModule.scala 58:23 59:13 62:13]
  assign io_out1 = row20 < row21 ? row21 : row20; // @[MyModule.scala 58:23 60:13 63:13]
  assign io_out2 = row22 < row23 ? row22 : row23; // @[MyModule.scala 66:23 67:13 70:13]
  assign io_out3 = row22 < row23 ? row23 : row22; // @[MyModule.scala 66:23 68:13 71:13]
endmodule

测试代码:

import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec

class MyModuleTest extends AnyFlatSpec with ChiselScalatestTester {
  behavior of "MyOperators"
  it should "get right results" in {
    test(new Sort4) { c =>
      // verify the inputs are sorted
      c.io.in0.poke(3.U)
      c.io.in1.poke(6.U)
      c.io.in2.poke(9.U)
      c.io.in3.poke(12.U)
      c.io.out0.expect(3.U)
      c.io.out1.expect(6.U)
      c.io.out2.expect(9.U)
      c.io.out3.expect(12.U)

      c.io.in0.poke(13.U)
      c.io.in1.poke(4.U)
      c.io.in2.poke(6.U)
      c.io.in3.poke(1.U)
      c.io.out0.expect(1.U)
      c.io.out1.expect(4.U)
      c.io.out2.expect(6.U)
      c.io.out3.expect(13.U)

      c.io.in0.poke(13.U)
      c.io.in1.poke(6.U)
      c.io.in2.poke(4.U)
      c.io.in3.poke(1.U)
      c.io.out0.expect(1.U)
      c.io.out1.expect(4.U)
      c.io.out2.expect(6.U)
      c.io.out3.expect(13.U)
    }
    println("SUCCESS!!")
  }
}

测试通过。

测试器也可以利用Scala中List的特性(Scala Standard Library 2.12.13 - scala.collection.immutable.List (scala-lang.org)),构造各种输入的排列组合:

test(new Sort4) { c =>
  List(1, 2, 3, 4).permutations.foreach { 
    case i0 :: i1 :: i2 :: i3 :: Nil => {
        println(s"Sorting $i0 $i1 $i2 $i3")
        c.io.in0.poke(i0.U)
        c.io.in1.poke(i1.U)
        c.io.in2.poke(i2.U)
        c.io.in3.poke(i3.U)
        c.io.out0.expect(1.U)
        c.io.out1.expect(2.U)
        c.io.out2.expect(3.U)
        c.io.out3.expect(4.U)
    }
    case _ => println(s"Matching Error!")
  }
}
println("SUCCESS!!")

这里的case是Scala的经典用法。前面List(1, 2, 3, 4).permutations.foreach得到的是各种排列的List的迭代器,每个List作为变量输入到后面的偏函数中。后面的case用于匹配模式,i0 :: i1 :: i2 :: i3是构造了一个模式,用于匹配列表中的四个值,功能相当于将列表中的值解包给四个变量。

感谢@浑水摸鱼大师 指出这里代码中的问题(见评论),目前已经修改:

博主,我是从头跟着你的帖子学习下来的,我在复现Sort4代码时,发现你简化版的Test里case i0 :: i1 :: i2 :: i3这行代码一直报错,应该修改为case i0 :: i1 :: i2 :: i3 :: Nil,意思是先创建一个空列表Nil,再逐步向列表头部添加元素i3、i2、i1、i0。

练习

多项式电路

x 2 − 2 x + 1 2 x 2 + 6 x + 3 4 x 2 − 10 x − 5 x^2 - 2x + 1\\ 2x^2 + 6x + 3\\ 4x^2 - 10x -5 x22x+12x2+6x+34x210x5

构造一个电路用于计算上面的多项式,一个选择器输入用于决定计算哪个多项式。

提示:使用Wire来存放 x 2 x^2 x2,这样就只需要计算一次了。

首先用测试驱动开发的思想用Scala写一个模型:

def poly0(x: Int): Int = {x * x - 2 * x + 1}
def poly1(x: Int): Int = {2 * x * x + 6 * x + 3}
def poly2(x: Int): Int = {4 * x * x - 10 * x - 5}

def main(args: Array[String]): Unit = {
    assert(poly0(0) == 1)
    assert(poly1(0) == 3)
    assert(poly2(0) == -5)

    assert(poly0(1) == 0)
    assert(poly1(1) == 11)
    assert(poly2(1) == -11)
}

测试通过,现在把这三个包装为一个参数化的函数,像硬件一样。使用Scala中的if语句,基于输入select选择对应的多项式:

def poly0(x: Int): Int = {x * x - 2 * x + 1}
def poly1(x: Int): Int = {2 * x * x + 6 * x + 3}
def poly2(x: Int): Int = {4 * x * x - 10 * x - 5}

def poly(select: Int, x: Int): Int = {
    if(select == 0) {
        poly0(x)
    } else if(select == 1) {
        poly1(x)
    } else {
        poly2(x)
    }
}

def main(args: Array[String]): Unit = {
    assert(poly(1, 0) == 3)
    assert(poly(1, 1) == 11)
    assert(poly(2, 1) == -11)
}

测试通过。

那我们现在按照原来的思路实现就行了:

import chisel3._
import chisel3.util._

class Polynomial extends Module {
  val io = IO(new Bundle {
    val select = Input(UInt(2.W))
    val x = Input(SInt(32.W))
    val out = Output(SInt(32.W))
  })

  val result = Wire(SInt(32.W))
  val square = Wire(SInt(32.W))

  square := io.x * io.x
  when(io.select === 0.U) {
    result := square - 2.S * io.x + 1.S
  }.elsewhen(io.select === 1.U) {
    result := 2.S * square + 6.S * io.x + 3.S
  }.otherwise {
    result := 4.S * square - 10.S * io.x -5.S
  }

  io.out := result
}

object Polynomial extends App {
  println(getVerilogString(new Polynomial))
}

输出如下:

module Polynomial(
  input         clock,
  input         reset,
  input  [1:0]  io_select,
  input  [31:0] io_x,
  output [31:0] io_out
);
  wire [63:0] _square_T = $signed(io_x) * $signed(io_x); // @[MyModule.scala 14:18]
  wire [34:0] _result_T = 3'sh2 * $signed(io_x); // @[MyModule.scala 16:28]
  wire [31:0] square = _square_T[31:0]; // @[MyModule.scala 12:20 14:10]
  wire [34:0] _GEN_3 = {{3{square[31]}},square}; // @[MyModule.scala 16:22]
  wire [34:0] _result_T_3 = $signed(_GEN_3) - $signed(_result_T); // @[MyModule.scala 16:22]
  wire [34:0] _result_T_6 = $signed(_result_T_3) + 35'sh1; // @[MyModule.scala 16:35]
  wire [34:0] _result_T_7 = 3'sh2 * $signed(square); // @[MyModule.scala 18:19]
  wire [35:0] _result_T_8 = 4'sh6 * $signed(io_x); // @[MyModule.scala 18:34]
  wire [35:0] _GEN_4 = {{1{_result_T_7[34]}},_result_T_7}; // @[MyModule.scala 18:28]
  wire [35:0] _result_T_11 = $signed(_GEN_4) + $signed(_result_T_8); // @[MyModule.scala 18:28]
  wire [35:0] _result_T_14 = $signed(_result_T_11) + 36'sh3; // @[MyModule.scala 18:41]
  wire [35:0] _result_T_15 = 4'sh4 * $signed(square); // @[MyModule.scala 20:19]
  wire [36:0] _result_T_16 = 5'sha * $signed(io_x); // @[MyModule.scala 20:35]
  wire [36:0] _GEN_5 = {{1{_result_T_15[35]}},_result_T_15}; // @[MyModule.scala 20:28]
  wire [36:0] _result_T_19 = $signed(_GEN_5) - $signed(_result_T_16); // @[MyModule.scala 20:28]
  wire [36:0] _result_T_22 = $signed(_result_T_19) - 37'sh5; // @[MyModule.scala 20:42]
  wire [36:0] _GEN_0 = io_select == 2'h1 ? $signed({{1{_result_T_14[35]}},_result_T_14}) : $signed(_result_T_22); // @[MyModule.scala 17:33 18:12 20:12]
  wire [36:0] _GEN_1 = io_select == 2'h0 ? $signed({{2{_result_T_6[34]}},_result_T_6}) : $signed(_GEN_0); // @[MyModule.scala 15:27 16:12]
  assign io_out = _GEN_1[31:0]; // @[MyModule.scala 11:20]
endmodule

测试代码如下:

import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec

class MyModuleTest extends AnyFlatSpec with ChiselScalatestTester {
  def poly0(x: Int): Int = {x * x - 2 * x + 1}
  def poly1(x: Int): Int = {2 * x * x + 6 * x + 3}
  def poly2(x: Int): Int = {4 * x * x - 10 * x - 5}
  def poly(select: Int, x: Int): Int = {
    if(select == 0) {
      poly0(x)
    } else if(select == 1) {
      poly1(x)
    } else {
      poly2(x)
    }
  }
  
  behavior of "MyOperators"
  it should "get right results" in {
    test(new Polynomial) { c =>
      for(x <- 0 to 20) {
        for(select <- 0 to 2) {
          c.io.select.poke(select.U)
          c.io.x.poke(x.S)
          c.io.out.expect(poly(select, x).S)
        }
      }
    }
    println("SUCCESS!!")
  }
}

测试通过。

有限状态机(FSM)

通过卡诺图来优化状态机逻辑太蛋疼了,可以用综合工具来优化,还会产生不直观、不可读的代码。而用Chisel的控制流和最后连接语义来编写是明智的选择。

一个硕士在学习生涯会经历四个状态:空闲(idel),写代码(coding),写论文(writing),毕业(graduate)。这几种状态的转换基于三种条件:咖啡,灵光乍现的idea,来自导师的pressure。一旦毕业了,就会回到空闲状态。

下面的FSM图展示了这些状态和它们之间的转换:

在这里插入图片描述

图中所有没标签的转换(即没有输入)都会返回到空闲状态而不是留在当前状态。输入的优先级是coffee > idea > pressure,所以当处于空闲状态的时候如果同时收到了咖啡和压力,就会转移到写代码状态。

下面是Scala的测试代码:

import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec

class MyModuleTest extends AnyFlatSpec with ChiselScalatestTester {
  def states = Map("idle" -> 0, "coding" -> 1, "writing" -> 2, "grad" -> 3)

  def gradLife (state: Int, coffee: Boolean, idea: Boolean, pressure: Boolean): Int = {
    var nextState = states("idle")
    if (state == states("idle")) {
      if (coffee) {nextState = states("coding")}
      else if (idea) {nextState = states("idle")}
      else if (pressure) {nextState = states("writing")}
    } else if (state == states("coding")) {
      if (coffee) {nextState = states("coding")}
      else if (idea || pressure) {nextState = states("writing")}
    } else if (state == states("writing")) {
      if (coffee || idea) {nextState = states("writing")}
      else if (pressure) {nextState = states("grad")}
    }
    nextState
  }

  (0 until states.size).foreach{ state => assert(gradLife(state, false, false, false) == states("idle")) }
  assert(gradLife(states("writing"), true, false, true) == states("writing"))
  assert(gradLife(states("idle"), true, true, true) == states("coding"))
  assert(gradLife(states("idle"), false, true, true) == states("idle"))
  assert(gradLife(states("grad"), false, false, false) == states("idle"))
}

目前还没学习到时序逻辑,所以这里的当前状态就用一个到模块的输入来表示,下一个状态就用一个输出来表示,跟上面的gradLife功能一致。现在用Chisel来实现。

Chisel提供了一个方便的状态机映射函数,叫做Enum,为了使用这些状态,将他们当作UInt字面值来使用。

注意,硬件上判断相等与否用的是三个等号===

实现如下:

import chisel3._
import chisel3.util._

class GradLife extends Module {
  val io = IO(new Bundle {
    val state = Input(UInt(2.W))
    val coffee = Input(Bool())
    val idea = Input(Bool())
    val pressure = Input(Bool())
    val nextState = Output(UInt(2.W))
  })

  val idle :: coding :: writing :: grad :: Nil = Enum(4)

  io.nextState := idle
  when(io.state === idle) {
    when(io.coffee) {
      io.nextState := coding
    }.elsewhen(io.idea) {
      io.nextState := idle
    }.elsewhen(io.pressure) {
      io.nextState := writing
    }
  }.elsewhen(io.state === coding) {
    when(io.coffee) {
      io.nextState := coding
    }.elsewhen(io.idea || io.pressure) {
      io.nextState := writing
    }
  }.elsewhen(io.state === writing) {
    when(io.coffee || io.idea) {
      io.nextState := writing
    }.elsewhen(io.pressure) {
      io.nextState := grad
    }
  }
}

object GradLife extends App {
  println(getVerilogString(new GradLife))
}

输出的Verilog代码如下:

module GradLife(
  input        clock,
  input        reset,
  input  [1:0] io_state,
  input        io_coffee,
  input        io_idea,
  input        io_pressure,
  output [1:0] io_nextState
);
  wire [1:0] _GEN_0 = io_pressure ? 2'h2 : 2'h0; // @[MyModule.scala 15:16 21:29 22:20]
  wire [1:0] _GEN_1 = io_idea ? 2'h0 : _GEN_0; // @[MyModule.scala 19:25 20:20]
  wire [1:0] _GEN_2 = io_coffee ? 2'h1 : _GEN_1; // @[MyModule.scala 17:21 18:20]
  wire [1:0] _GEN_3 = io_idea | io_pressure ? 2'h2 : 2'h0; // @[MyModule.scala 15:16 27:40 28:20]
  wire [1:0] _GEN_4 = io_coffee ? 2'h1 : _GEN_3; // @[MyModule.scala 25:21 26:20]
  wire [1:0] _GEN_5 = io_pressure ? 2'h3 : 2'h0; // @[MyModule.scala 15:16 33:29 34:20]
  wire [1:0] _GEN_6 = io_coffee | io_idea ? 2'h2 : _GEN_5; // @[MyModule.scala 31:32 32:20]
  wire [1:0] _GEN_7 = io_state == 2'h2 ? _GEN_6 : 2'h0; // @[MyModule.scala 15:16 30:36]
  wire [1:0] _GEN_8 = io_state == 2'h1 ? _GEN_4 : _GEN_7; // @[MyModule.scala 24:35]
  assign io_nextState = io_state == 2'h0 ? _GEN_2 : _GEN_8; // @[MyModule.scala 16:27]
endmodule

测试代码如下:

import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec

class MyModuleTest extends AnyFlatSpec with ChiselScalatestTester {
  def states = Map("idle" -> 0, "coding" -> 1, "writing" -> 2, "grad" -> 3)

  def gradLife (state: Int, coffee: Boolean, idea: Boolean, pressure: Boolean): Int = {
    var nextState = states("idle")
    if (state == states("idle")) {
      if (coffee) {nextState = states("coding")}
      else if (idea) {nextState = states("idle")}
      else if (pressure) {nextState = states("writing")}
    } else if (state == states("coding")) {
      if (coffee) {nextState = states("coding")}
      else if (idea || pressure) {nextState = states("writing")}
    } else if (state == states("writing")) {
      if (coffee || idea) {nextState = states("writing")}
      else if (pressure) {nextState = states("grad")}
    }
    nextState
  }
  
  behavior of "MyOperators"
  it should "get right results" in {
    test(new GradLife) { c =>
      for (state <- 0 to 3) {
        for (coffee <- List(true, false)) {
          for (idea <- List(true, false)) {
            for (pressure <- List(true, false)) {
              c.io.state.poke(state.U)
              c.io.coffee.poke(coffee.B)
              c.io.idea.poke(idea.B)
              c.io.pressure.poke(pressure.B)
              c.io.nextState.expect(gradLife(state, coffee, idea, pressure).U)
            }
          }
        }
      }
    }
    println("SUCCESS!!")
  }
}

测试通过。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Chisel教程——04.Chisel中的控制流 的相关文章

  • Scala 程序中三元运算符的用法[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我有一个需要应用过滤器的对象数组 val filteredList list filter l gt pid true l Pro
  • sh / Bash shell 脚本中 !# (bang-pound) 的含义是什么?

    我想了解这个 Scala 脚本是如何工作的 usr bin env bash exec scala 0 object HelloWorld def main args Array String println Hello world arg
  • 使用 mapWithState Spark Streaming 过滤部分重复项

    我们有一个DStream 比如 val ssc new StreamingContext sc Seconds 1 val kS KafkaUtils createDirectStream String TMapRecord ssc Pre
  • 具有通用返回类型的可选函数参数

    您将如何实现通过正则表达式解析某些输入并将创建的字符串转换为其他类型的类 我的做法是 class ARegex T regex Regex reform Option String gt T def findFirst input Stri
  • 解释一下 Scala 中 Y 组合器的实现?

    这是 Y 组合器在 Scala 中的实现 scala gt def Y T func T gt T gt T gt T T gt T func Y func T Y T func T gt T gt T gt T T gt T scala
  • 从apache Spark中的文本文件查找rdd中存储的数据大小

    我是 Apache Spark 版本 1 4 1 的新手 我编写了一段小代码来读取文本文件并将其数据存储在 Rdd 中 有没有一种方法可以获取 rdd 中数据的大小 这是我的代码 import org apache spark SparkC
  • 在 Scala 中设计方便的默认值映射

    我发现自己使用了很多嵌套映射 例如 Map Int Map String Set String 并且我希望在访问新密钥时自动创建新的 Map Set 等 例如 像下面这样 val m m 1992 foo bar 请注意 如果不需要 我不想
  • Scala:var List 与 val MutableList

    在 Odersky 等人的 Scala 书中 他们说使用列表 我还没有从头到尾读过这本书 但所有的例子似乎都使用了 val List 据我了解 还鼓励人们使用 vals 而不是 vars 但在大多数应用程序中 使用 var List 或 v
  • 由于 UTFDataFormatException 导致 Spark 中的任务无法序列化:编码字符串太长

    我在 Yarn 上运行 Spark 应用程序时遇到一些问题 我有非常广泛的集成测试 运行时没有任何问题 但是当我在 YARN 上运行应用程序时 它将抛出以下错误 17 01 06 11 22 23 ERROR yarn Applicatio
  • Scala 除以零会产生不同的结果

    我对 Scala 如何处理除以零感到困惑 这是 REPL 代码片段 scala gt 1 0 java lang ArithmeticException by zero 33 elided scala gt 1 toDouble 0 toD
  • 使用 Scala Slick 创建组合主键

    我正在尝试使用两列作为 Scala Slick 表的主键 这是我的表的定义方式 class NbaPlayerBoxScoreTable tag Tag extends Table NbaPlayerBoxScore tag player
  • Scala+Slick 3:将一个查询的结果插入到另一张表中

    这个问题是关于 slick 3 0 或 3 1 的 我对此很灵活 我有一个中间查询 我用它来处理map for等等以获得我想要的结果 最后我有一个 val foo DBIOAction Seq MySchema Bar NoStream E
  • 通过spark-shell以静默模式执行scala脚本

    需要通过spark shell以静默模式执行scala脚本 当我使用时spark shell i file scala 执行后 我进入scala交互模式 我不想进入那里 我尝试执行spark shell i file scala 但我不知道
  • 组合多个任意长度的列表

    我正在寻找一种通过以下方式加入多个列表的方法 ListA a b c ListB 1 2 3 4 ListC Resulting List a 1 b 2 c 3 4 换句话说 元素按顺序排列 从第一个列表开始组合到结果列表中 任意数量的输
  • kafka ProducerRecord 和 KeyedMessage 有什么区别

    我正在衡量卡夫卡生产者生产者的表现 目前我遇到了两个配置和用法略有不同的客户 Common def buildKafkaConfig hosts String port Int Properties val props new Proper
  • 如何从 lift webapp 读取文件

    我想在我的 lift 应用程序中读取 xml 文件 val data XML load new java io InputStreamReader new java io FileInputStream 文件名 编码 然而 我得到java
  • 组合部分函数

    我有两个偏函数f and g 它们没有副作用并且执行速度快 将它们组合成另一个部分函数的最佳方法是什么h这样h isDefinedAt x iff f isDefinedAt x g isDefinedAt f x 如果h是一个返回一个函数
  • 如何识别远程参与者?

    我有一个远程参与者 客户端 它正在向另一个远程参与者 服务器 注册 然后注销 使用关闭挂钩 然而 虽然服务器接收到注销 但实际sender财产是一个不同的 Channel 对象 所以在我的服务器日志中我有 Registered new cl
  • scala 中的模拟案例类:Mockito

    在我的游戏应用程序中 我打算模拟一个案例类 我可以这样做 但它创建了一个所有成员变量都为空的对象 有没有办法创建案例类的模拟对象 以便该对象可以初始化一些成员 case class User name String address Stri
  • sbt:编译测试时设置特定的 scalacOptions 选项

    通常我使用这组选项来编译 Scala 代码 scalacOptions Seq deprecation encoding UTF 8 feature unchecked language higherKinds language impli

随机推荐

  • 首次进入小程序拒绝相机权限,再次允许camera组件显示不出来

    第一次进去拒绝授权开启摄像头后 再次进去允许授权 但是页面camera组件显示不出来 百度了一下 大家都说直接给camera组件写个显示隐藏 试过了 不是很理想 最终想到的解决办法 拒绝授权后进入的方法 官方的函数名 handleCamer
  • sqli-labs:less-21

    和20题很像 然后一看cookie是一个base64编码的 解码一下 是Dumb 所以cookie一个是注入点 只是有个base64编码 随便提一下 base32 只有大写字母和数字数字组成 或者后面有三个等号 base64 只有大写字母和
  • 【MATLAB】使用Classification Learner工具箱训练和预测数据

    近日对matlab内置的classification Learner 工具箱有所接触 现在整理一下关于使用该工具箱训练模型和预测数据的相关操作 一 原始数据 其中列向量为样本 行向量内为每个样本的6个特征 最后一列为样本的响应变量 即为样本
  • PyCharm社区版安装教程和环境配置及使用

    一 PyCharm官网下载 访问官网地址 https www jetbrains com pycharm 点击首页 Download 按钮 进入下载页面 选择Community下的 Download 如图 点击后进入 Thank you f
  • ntp服务器修改时区,部署ntp服务器笔记与时区的介绍与修改

    准备工作 server ip 10 1 1 119 client ip 10 1 1 56 关闭selinux vi etc selinux config SELINUX disabled 关闭iptables service iptabl
  • 时序分析基本概念介绍——SDC概述

    今天我们要介绍的时序概念是设计约束文件SDC 全称Synopsys design constraints SDC是一个设计中至关重要的一个文件 它对电路的时序 面积 功耗进行约束 它是设计的命脉 决定了芯片是否满足设计要求的规范 Timin
  • C++ vs2015编译json和protobuf报错nlohmann::detail::static_constnlohmann::detail::to_json_fn::value‘

    目录 问题描述 解决方案 参考连接 问题描述 补充 这个问题也会导致protobuf编译和使用报错 按照本方法修复后问题解决 只要引入项目中的 include nlohmann json hpp 用vs2015编译就会报错 甚至用vs202
  • Swift里的元组和可选类型

    文章目录 元组 Tuples 定义一个元组 元组作为函数的返回值 元组的适用范围 可选类型 Optionals 定义可选类型 示例分析 Optional中使用nil 元组 Tuples 元组将多个值分组为一个复合值 元祖中的值可以是任何类型
  • Stream filter()过滤有效数据

    filter 是一个中间操作 可以与 reduce collect map 等一起使用 filter一般适用于list集合 主要作用就是模拟sql查询 从集合中查询想要的数据 java官方文档语法如下 filter Predicate pr
  • 迭代器失效问题

    1 什么是迭代器失效 迭代器失效是一种现象 由特定操作引发 这些特定操作对容器进行操作 使得迭代器不指向容器内的任何元素 或者使得迭代器指向的容器元素发生了改变 2 可能引起迭代器失效的操作 插入元素 扩容引起的迭代器指向的元素或者空间发生
  • python矩阵_Python矩阵

    python矩阵 In this tutorial we will learn about Python Matrix In our previous tutorial we learnt about Python JSON operati
  • 【python 学习 01】命名规范

    命名其实是一个非常重要的事 根据Python之父Guido推荐的命名规范包括如下几点 包名 模块名 局部变量名 函数名 全小写 下划线式驼峰 example this is var 全局变量 全大写 下划线式驼峰 example GLOBA
  • Zabbix---5 监控linux服务器目录大小

    例如监控 root data 目录 一 添加自己脚本 root localhost sbin pwd usr local sbin root localhost sbin cat dir size sh bin bash du m root
  • STM32的CAN总线的接收双FIFO使用方法

    通过下面的框图我们可以看到 STM32F013有两个接收FIFO 但是实际的使用中如何让着两个FIFO都被使用呢 解决办法就在这里 1 STM32F103有0 13共14个过滤器组 每个过滤器组都可以绑定指定的FIFO 2 特别需要注意的一
  • K8s学习笔记二:Ubuntu安装minikube以及K8s简单体验

    Ubuntu安装minikube官方文档看这里 完成Docker十分钟了解Docker 我的Docker学习笔记 和kubectlUbuntu安装kubectl的下载安装后 就可以进行minikube的安装了 它能够帮助我们在本地非常容易的
  • 20145334 《信息安全系统设计基础》第8周学习总结

    转眼已经到了期中复习 听弟弟妹妹们说他们要期中考试了 我们大三上学期的课程也已经过半 考试试题 发现问题及时沟通 首先看一下每周检测解析 这个是比较重要的内容 也是复习和巩固所学知识点的好帮手 下面是老师给出的解析链接 https grou
  • 【mac 安全渗透测试】之SQL注入Demo

    一 关于sqlmap的介绍 1 SQLmap工具简介 SQLmap是一款开源的SQL注入漏洞检测 利用工具 可以检测动态页面中get post参数 cookie http头 它由Python语言开发而成 运行需要安装python环境 在ka
  • arm64架构的linux中断分析(零)

    文章目录 1 中断的概念和作用 2 Linux中断处理机制 2 1 中断请求 2 2 中断处理 2 3 中断完成 2 4 中断触发和处理步骤详解 2 4 1 异常向量表的解读 3 GICv3中断控制器 3 1 GICv3中断控制器设备树 3
  • 触摸屏tslib库交叉编译并移植ARM校准测试

    本文介绍 触摸屏tslib库交叉编译并移植ARM 校准及测试 下载tslib Tags libts tslib GitHub 在tslib的官方github上选择一个版本下载即可 本实验版本为 tslib 1 12 tar gz 1 配置
  • Chisel教程——04.Chisel中的控制流

    控制流 动机 本系列到目前为止 Chisel中的软硬件之间都有很强的对应关系 但引入控制流之后就不一样了 对软硬件的看法就应该有很大的分歧了 本节会在生成器软件和硬件中都引入控制流 如果重新连接到一个Chisel连线会怎么样呢 如何让一个多