Scala:如何测试可变表的并发性 [英] Scala: How to test the concurrency of a mutable.Set

查看:78
本文介绍了Scala:如何测试可变表的并发性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Scala中,并发和非并发Set的类型完全相同:

In Scala, both concurrent and non-concurrent Sets have exactly the same type:

import collection.JavaConverters._

// A regular Set in Scala, not concurrent.
val regularSet: mutable.Set[Int] = mutable.Set[Int]()

// A concurrent set. It has the same type as a regular set, but underneath, it is actually concurrent. In my opinion, this is a flaw in the type system for Scala collections
val concurrentSet: mutable.Set[Int] = java.util.concurrent.ConcurrentHashMap.newKeySet[Int]().asScala

我想要一种实际测试集合是否并发的方法。

I'd like a way to actually test whether a set is concurrent or not.

推荐答案

答案

您可以通过创建大量尝试执行的线程来进行经验测试从共享的 mutable.Set

You can test it empirically by creating a lot of threads which are trying to add/remove the same elements from a shared mutable.Set

import java.util.concurrent.{Callable, ExecutorService, Executors}
import scala.collection.mutable

def testSet(set: mutable.Set[Int]) {
  val e: ExecutorService = Executors.newFixedThreadPool(5)
  val tasks = for (i <- 0 to 50000) yield {
    e.submit(new Callable[Unit]() {
      override def call() {
        for (j <- 0 to 10) {
          set.add(i + j)

          // This will throw a Null Pointer Exception for the non-concurrent version
          // This is because it is trying to remove something that another thread already removed.
          set.remove(i + j) 
        }
      }
    })
  }
  for (result <- tasks) result.get()
  e.shutdown()
}

// Can't check the type! They have the same type.
val regularSet: mutable.Set[Int] = mutable.Set[Int]()
val concurrentSet: mutable.Set[Int] = java.util.concurrent.ConcurrentHashMap.newKeySet[Int]().asScala

testSet(concurrentSet) // Success!
testSet(regularSet) // FAILS! Almost always throws a NullPointerException on my system.

限制

运行测试将需要系统资源,例如线程和CPU时间。

Running the test will require system resources such as threads and CPU time. It is not really appropriate to run this in production at runtime.

这不是演绎证明。由于竞争条件是随机的,因此测试极有可能将非并发对象分类为并发对象。但是,长时间运行测试将导致检测到非并发对象接近确定性的可能性。

This is not a deductive proof. There is a tiny chance that the test will classify a non-concurrent object as being concurrent, since the race condition is random. However, running the test for longer will cause the probability of detecting non-concurrent objects to approach certainty.

其他注释

理想情况下,有一种方法可以使用反射和类型系统来查看底层对象是什么,并测试它是否为 ConcurrentHashMap 是否存在(我认为Scala的主要缺陷,因为运行多线程任务的某些函数无法有效地阻止函数调用者传入非并发对象)。

Ideally there would be a way to use reflection and the type system to see what the underlying object was and test if it was a ConcurrentHashMap or not (major flaw in Scala in my opinion, since some function that runs a multi-threaded task cannot effectively prevent the the function caller from passing in a non-concurrent object).

但这至少提供了一种检验它的经验方法。

But this at least provides an empirical way to test it.

致谢

如何提出类似的问题测试ConcurrentHashMap是否真正是线程安全的?。我已经对其进行了修改以与Sets一起使用:

A similar question was asked in How can I test that ConcurrentHashMap is truly thread-safe? . I've modified it to work with Sets:

推荐

我会建议使用 current.Map [T,Unit] 而不是 mutable.Set [T] 。原因是您将能够利用类型系统,以100%的置信度确保函数/类所操作的对象实际上是并发的。

I would recommend using a concurrent.Map[T, Unit] rather than mutable.Set[T]. The reason is that you will be able to leverage the type system to ensure, with 100% confidence, that the object your function/class operates on is actually concurrent.

是,您将失去Set语义,例如 .add(setMember)方法。但是,您将获得安全。

Yes, you will lose the Set semantics, such as the .add(setMember) method. But you will gain safety.

如果您坚持使用并发的 mutable.Set ,请考虑制作包装器类容器,这样就可以防止意外初始化为非并发 mutable.Set

If you insist on using a concurrent mutable.Set, consider making a wrapper class container so that you can prevent accidental initialization to a non-concurrent mutable.Set.

这篇关于Scala:如何测试可变表的并发性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆