并行程序中的Scala模式匹配

并行程序中的Scala模式匹配,scala,concurrency,pattern-matching,Scala,Concurrency,Pattern Matching,我是Scala新手,我想写一些带有模式匹配的多线程代码,我想知道是否可以将模式匹配代码视为原子代码 例如: abstract class MyPoint case class OneDim(x : Int) extends MyPoint case class TwoDim(x : Int, y : Int) extends MyPoint var global_point : MyPoint = new OneDim(7) spawn { Thread.sleep(scala.ut

我是Scala新手,我想写一些带有模式匹配的多线程代码,我想知道是否可以将模式匹配代码视为原子代码

例如:

abstract class MyPoint
case class OneDim(x : Int) extends MyPoint
case class TwoDim(x : Int, y : Int) extends MyPoint

var global_point : MyPoint = new OneDim(7)

spawn {
    Thread.sleep(scala.util.Random.nextInt(100))
    global_point = new TwoDim(3, 9)
}
Thread.sleep(scala.util.Random.nextInt(100))

match global_point {
    case TwoDim(_, _) => println("Two Dim")
    case OneDim(_) => println("One Dim")
}
是否可能按照以下方式执行:

  • 主线程到达“match global_point”代码,发现*global_point*不是TwoDim类型并暂停(返回调度程序)
  • 生成的线程将*global_point*更改为TwoDim类型
  • 主线程返回,发现*global_point*不是OneDim类型,认为没有与*global_point*匹配的项,并引发NoMatch异常

  • Scala是否在内部避免了这种执行?如果是这样的话,怎么办?匹配是否拍摄对象的快照,然后尝试将其与模式匹配?快照深度是否有限制(匹配模式可能是复杂的和嵌套的)?

    我不认为为模式匹配生成的代码中存在任何类型的锁定或快照。如果是,它肯定会在语言规范中提到。这就是说,如果您将模式匹配代码放入一个方法中,您至少可以确保该方法所传递的引用在该方法执行时不会更改。如果TwoDim和OneDim也是不可变的,那么就不需要担心线程安全性。即使它们不是不可变的,只要您在它们的可变字段之一上不匹配也无所谓。

    在Scala中,首选的并发解决方案是使用
    Actor
    s。在那些
    Actor
    s中,您需要使用模式匹配来添加行为。我使用scalas
    Actor
    构建了一个与您类似的示例

    import scala.actors.Actor
    import scala.actors.Actor._
    
    abstract class MyPoint
    case class OneDim(x: Int) extends MyPoint
    case class TwoDim(x: Int, y: Int) extends MyPoint
    
    case object Next
    case object End
    
    class OneDimSlave extends Actor {
    
      def act() {
        println("Starting OneDimSlave")
      loop {
            receive {
              case End => println("Stoping OneDimSlave"); exit()
              case Next => sender ! OneDim(scala.util.Random.nextInt(100))
            }
          }
    }
    
    }
    
    class TwoDimSlave extends Actor {
    
      def act() {
        println("Starting TwoDimSlave")
      loop {
        receive {
          case End => println("Stopping TwoDimSlave"); exit()
          case Next => sender ! TwoDim(scala.util.Random.nextInt(100),scala.util.Random.nextInt(100))
        }
      }
    }
    
    }
    
    class Master extends Actor {
    
      val oneDimSlave = new OneDimSlave
      val twoDimSlave = new TwoDimSlave
    
      oneDimSlave.start
      twoDimSlave.start
    
      def act {
        println("Starting Master")
    for (_ <- 0 to 9) { oneDimSlave ! Next; twoDimSlave ! Next }
    var count = 0
    loop {
      if (count >= 20) { oneDimSlave ! End; twoDimSlave ! End; println("Stopping Master"); exit() }
      receive {
        case _ :OneDim => count += 1; println(count + ". One Dim")
        case _: TwoDim => count += 1; println(count + ". Two Dim")
      }
    }
      }
    
    }
    
    object Main extends App {
      val master = new Master
      master.start
    }
    

    这不是来自规范的确凿证据,但它说明了编译器为您所做的一些事情,这应该允许您将少数匹配块视为原子块,但肯定不是所有的。如果您自己同步代码,或者使用不可变对象,则会更加安全

    简单的例子 如果使用scala-print运行以下脚本:

    var m: Option[String] = _
    
    m match {
      case Some(s) => "Some: " + s
      case None => "None"
    }
    
    您将看到由编译器创建的经过去糖处理的中间代码(为了简洁起见,我删除了一些代码):

    编译器将创建以下中间代码:

    private[this] var x: anonymous class Main$$anon$1$X = _;
    
    private <accessor> def x(): anonymous class Main$$anon$1$X = Main$$anon$1.this.x;
    
    final <synthetic> private[this] def gd2$1(x$1: Int, x$2: anonymous class Main$$anon$1$X): Boolean = x$1.>(0).||(x$2.f().>(0));
    
    final <synthetic> private[this] def gd3$1(x$1: Int, x$2: anonymous class Main$$anon$1$X): Boolean = x$1.<=(0).||(x$2.f().<=(0));
    
    def this(): anonymous class Main$$anon$1 = {
      <synthetic> val temp6: anonymous class Main$$anon$1$X = Main$$anon$1.this.x();
    
      if (temp6.ne(null)) {
        <synthetic> val temp7: Int = temp6.f();
        <synthetic> val temp8: anonymous class Main$$anon$1$X = temp6.x();
        
        if (Main$$anon$1.this.gd2$1(temp7, temp8))
          "gt0"
        else if (Main$$anon$1.this.gd3$1(temp7, temp8))
          "lte0"
        else
          throw new MatchError(temp6)
      } else
        throw new MatchError(temp6)
    }
    
    private[this]变量x:匿名类Main$$anon$1$x=\;
    private def x():匿名类Main$$anon$1$x=Main$$anon$1.this.x;
    final private[this]def gd2$1(x$1:Int,x$2:anonymous类Main$$anon$1$x):Boolean=x$1.>(0)。| |(x$2.f().>(0));
    final private[this]def gd3$1(x$1:Int,x$2:anonymous类Main$$anon$1$x):Boolean=x$1。
    
    final class Main$$anon$1 extends java.lang.Object {
      private[this] var m: Option = _;
    
      private <accessor> def m(): Option = Main$$anon$1.this.m;
    
      def this(): anonymous class Main$$anon$1 = {
        <synthetic> val temp1: Option = Main$$anon$1.this.m();
    
        if (temp1.$isInstanceOf[Some]()) {
          "Some: ".+(temp1.$asInstanceOf[Some]().x())
        else if (scala.this.None.==(temp1))
          "None"
        else
          throw new MatchError(temp1)
      }
    }
    
    case class X(var f: Int, var x: X)
    
    var x = new X(-1, new X(1, null))
    
    x match {
      case X(f, ix) if f >  0 || ix.f > 0  => "gt0"
      case X(f, ix) if f <= 0 || ix.f <= 0 => "lte0"
    }
    
    private[this] var x: anonymous class Main$$anon$1$X = _;
    
    private <accessor> def x(): anonymous class Main$$anon$1$X = Main$$anon$1.this.x;
    
    final <synthetic> private[this] def gd2$1(x$1: Int, x$2: anonymous class Main$$anon$1$X): Boolean = x$1.>(0).||(x$2.f().>(0));
    
    final <synthetic> private[this] def gd3$1(x$1: Int, x$2: anonymous class Main$$anon$1$X): Boolean = x$1.<=(0).||(x$2.f().<=(0));
    
    def this(): anonymous class Main$$anon$1 = {
      <synthetic> val temp6: anonymous class Main$$anon$1$X = Main$$anon$1.this.x();
    
      if (temp6.ne(null)) {
        <synthetic> val temp7: Int = temp6.f();
        <synthetic> val temp8: anonymous class Main$$anon$1$X = temp6.x();
        
        if (Main$$anon$1.this.gd2$1(temp7, temp8))
          "gt0"
        else if (Main$$anon$1.this.gd3$1(temp7, temp8))
          "lte0"
        else
          throw new MatchError(temp6)
      } else
        throw new MatchError(temp6)
    }