加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

并发程序中的Scala模式匹配

发布时间:2020-12-16 18:18:19 所属栏目:安全 来源:网络整理
导读:我是 Scala的新手,我想编写一些带有模式匹配的多线程代码,我想知道我是否可以将模式匹配代码视为原子. 例如: abstract class MyPointcase class OneDim(x : Int) extends MyPointcase class TwoDim(x : Int,y : Int) extends MyPointvar global_point : MyP
我是 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内部是否避免了这种执行?如果确实如此,那怎么样?匹配是否拍摄对象的快照,然后尝试将其与模式匹配?快照深度是否有限制(匹配模式可以是复杂的和嵌套的)?

解决方法

这不是规范中的确凿证据,但它说明了编译器为您做的一些事情,这应该允许您将几个匹配块视为原子 – 但绝对不是全部.如果您自己同步代码,或者使用不可变对象,则会更安全.

平面的例子

如果使用scala -print运行以下脚本:

var m: Option[String] = _

m match {
  case Some(s) => "Some: " + s
  case None => "None"
}

你会看到编译器创建的desugared中间代码(为了简洁,我删除了一些代码):

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)
  }
}

m引用的可能共享对象获取本地别名temp1,因此如果在后台更改m以使其指向另一个对象,则匹配仍将发生在指向的旧对象上.因此,上面描述的情况(将global_point更改为指向TwoDim而不是OneDim)将不会成为问题.

嵌套的例子

通常情况下,编译器会为绑定在匹配大小写中的所有对象创建本地别名,但它不会创建深层副本!
对于以下脚本:

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)
}

这里,编译器为你匹配的对象x创建本地别名,并为它的两个子对象x.f(绑定到f)和x.x(绑定到ix),但不是为ix.f.因此,如果您匹配的结构是深度嵌套的,并且您的案例依赖于您未在本地绑定的嵌套对象,则可能会出现竞争条件.而且,正如我们都知道墨菲所知道的那样.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读