我有两个填充数组[Int]的实现,如下所述。第一个以84毫秒的速度执行,第二个以100倍的速度执行:
Execute 'filling via Array.fill' in 84 ms
Execute 'filling via while' in 8334 ms
为什么第二个变种需要100倍以上的时间?它不是GC,因为我可以删除第一次执行,同时删除第二次执行。我使用Scala 3在Java 11上运行它:
.jdks/adopt-openjdk-11.0.11/bin/java ... Fill
更重要的是,如果你打开数组。填充
implementation,您将通过while。。。
object Fill extends App {
def timeMeasure[R](name: String)(block: => R): R = {
val startTime = System.currentTimeMillis()
val r = block
val endTime = System.currentTimeMillis()
println(s"Execute '$name' in ${endTime - startTime} ms")
r
}
val n = 1000 * 1000 // * 10
var ar = timeMeasure("filling via Array.fill") {
Array.fill[Int](n)(10)
}
ar = timeMeasure("filling via while") {
val array = new Array[Int](n)
var i = 0
while (i < n) {
array(i) = i
i += 1
}
array
}
}
PS:我在Scala 2.12上重复这个测试:
Execute 'filling via Array.fill' in 118 ms
Execute 'filling via while' in 6 ms
所以Scala 3的问题...
PPS:在这种情况下,for(i)
购买力平价:对于那些认为它是随机的或是其他什么的人来说,它不是:100个测试执行516秒(今天我的电脑更快),所以平均时间太长了。但无论如何,在一些程序中,一些代码块只执行一个,所以您不应该执行任何性能测试的平均时间。
更新:我发现当
val n
位于代码块之外时,执行时间大约慢了1000倍。但是我不明白为什么。
您可以在Scala 3编译器的存储库中看到对此问题的评论:https://github.com/lampepfl/dotty/issues/13819
Scala 3使用这段代码做了一些非常奇怪的事情。
如果我在不改变逻辑的情况下将其重构为不同的结构,那么一切都会按预期工作(Array.fill
比while
慢一点)。
object Fill extends App {
def timeMeasure[R](f: => R): (java.lang.Long, R) = {
val startTime = System.nanoTime()
val r = f
val endTime = System.nanoTime()
(endTime - startTime, r)
}
def warmup(): Unit = {
println("== warmup start =====================")
for (i <- 0 to 10) {
measureForN(1000000)
}
println("== warmup finish =====================")
}
def measureForN(n: Int): Unit = {
val t1 = timeMeasure { Array.fill[Int](n)(10) }
val t2 = timeMeasure({
val array = new Array[Int](n)
var i = 0
while (i < n) {
array(i) = 10
i += 1
}
array
})
val t3 = timeMeasure({
val array = new Array[Int](n)
var i = 0
while (i < n) {
array(i) = i
i += 1
}
array
})
// just to ensure actual array creations
val length = List(t1._2.length, t2._2.length, t3._2.length).min
println(s"n: ${n}, length: ${length}, fill: ${t1._1 / 1000} μs , while constant: ${t2._1 / 1000} μs, while changing: ${t3._1 / 1000} μs")
}
warmup()
measureForN(10)
measureForN(100)
measureForN(1000)
measureForN(10000)
measureForN(100000)
measureForN(1000000)
measureForN(10000000)
measureForN(100000000)
}
输出:
== warmup start =====================
n: 1000000, length: 1000000, fill: 23533 μs , while constant: 3804 μs, while changing: 3716 μs
n: 1000000, length: 1000000, fill: 7070 μs , while constant: 1606 μs, while changing: 1783 μs
n: 1000000, length: 1000000, fill: 3911 μs , while constant: 1497 μs, while changing: 1689 μs
n: 1000000, length: 1000000, fill: 3821 μs , while constant: 1543 μs, while changing: 1718 μs
n: 1000000, length: 1000000, fill: 3798 μs , while constant: 1510 μs, while changing: 1662 μs
n: 1000000, length: 1000000, fill: 3801 μs , while constant: 1524 μs, while changing: 1796 μs
n: 1000000, length: 1000000, fill: 3896 μs , while constant: 1541 μs, while changing: 1703 μs
n: 1000000, length: 1000000, fill: 3805 μs , while constant: 1486 μs, while changing: 1687 μs
n: 1000000, length: 1000000, fill: 3854 μs , while constant: 1606 μs, while changing: 1712 μs
n: 1000000, length: 1000000, fill: 3836 μs , while constant: 1509 μs, while changing: 1698 μs
n: 1000000, length: 1000000, fill: 3846 μs , while constant: 1553 μs, while changing: 1672 μs
== warmup finish =====================
n: 10, length: 10, fill: 3 μs , while constant: 0 μs, while changing: 0 μs
n: 100, length: 100, fill: 2 μs , while constant: 3 μs, while changing: 0 μs
n: 1000, length: 1000, fill: 6 μs , while constant: 1 μs, while changing: 2 μs
n: 10000, length: 10000, fill: 41 μs , while constant: 19 μs, while changing: 17 μs
n: 100000, length: 100000, fill: 378 μs , while constant: 156 μs, while changing: 170 μs
n: 1000000, length: 1000000, fill: 3764 μs , while constant: 1464 μs, while changing: 1676 μs
n: 10000000, length: 10000000, fill: 36976 μs , while constant: 15687 μs, while changing: 10860 μs
n: 100000000, length: 100000000, fill: 312242 μs , while constant: 190274 μs, while changing: 221980 μs
编辑::所需的更改非常简单,只要不直接使用块中的
n
。
object Fill extends App {
def timeMeasure[R](name: String)(block: => R): R = {
val startTime = System.currentTimeMillis()
val r = block
val endTime = System.currentTimeMillis()
println(s"Execute '$name' in ${endTime - startTime} ms")
r
}
val n = 1000 * 1000 // * 10
def measureFill(x: Int): Unit = {
val ar1 = timeMeasure("filling via Array.fill") {
Array.fill[Int](x)(10)
}
}
def measureWhile(x: Int): Unit = {
val ar2 = timeMeasure("filling via while") {
val array = new Array[Int](x)
var i = 0
while (i < x) {
array(i) = i
i += 1
}
array
}
}
println("== warmup ==================")
measureFill(n)
measureWhile(n)
println("== warmup ==================")
measureFill(n)
measureWhile(n)
}
输出:
== warmup start ==================
Execute 'filling via Array.fill' in 26 ms
Execute 'filling via while' in 5 ms
== warmup finish ==================
Execute 'filling via Array.fill' in 6 ms
Execute 'filling via while' in 1 ms
编辑2:: 正如Mikhail所指出的,这是因为
n
的用法与生成Java代码中方法n()
的用法相同。
object Test3 {
val n = 1
val k = n
}
正在被编译成,
//decompiled from Test3.class
public final class Test3 {
public static int k() {
return Test3$.MODULE$.k();
}
public static int n() {
return Test3$.MODULE$.n();
}
}
//decompiled from Test3$.class
import java.io.Serializable;
import scala.runtime.ModuleSerializationProxy;
public final class Test3$ implements Serializable {
private static final int n = 1;
private static final int k;
public static final Test3$ MODULE$ = new Test3$();
private Test3$() {
}
static {
k = MODULE$.n();
}
private Object writeReplace() {
return new ModuleSerializationProxy(Test3$.class);
}
public int n() {
return n;
}
public int k() {
return k;
}
}
但是,Scala 2.13.6生成的Java代码几乎相同(只是ScalaSignature部分不同)。
//decompiled from Test3.class
import scala.reflect.ScalaSignature;
@ScalaSignature(
bytes = "\u0006\u0005\r:Qa\u0002\u0005\t\u0002=1Q!\u0005\u0005\t\u0002IAQ!G\u0001\u0005\u0002iAqaG\u0001C\u0002\u0013\u0005A\u0004\u0003\u0004!\u0003\u0001\u0006I!\b\u0005\bC\u0005\u0011\r\u0011\"\u0001\u001d\u0011\u0019\u0011\u0013\u0001)A\u0005;\u0005)A+Z:ug)\u0011\u0011BC\u0001\ta\u0016\u0014X.\u00192be*\u00111\u0002D\u0001\u0005g\u0016\u0014\u0018NC\u0001\u000e\u0003\tiWm\u0001\u0001\u0011\u0005A\tQ\"\u0001\u0005\u0003\u000bQ+7\u000f^\u001a\u0014\u0005\u0005\u0019\u0002C\u0001\u000b\u0018\u001b\u0005)\"\"\u0001\f\u0002\u000bM\u001c\u0017\r\\1\n\u0005a)\"AB!osJ+g-\u0001\u0004=S:LGO\u0010\u000b\u0002\u001f\u0005\ta.F\u0001\u001e!\t!b$\u0003\u0002 +\t\u0019\u0011J\u001c;\u0002\u00059\u0004\u0013!A6\u0002\u0005-\u0004\u0003"
)
public final class Test3 {
public static int k() {
return Test3$.MODULE$.k();
}
public static int n() {
return Test3$.MODULE$.n();
}
}
//decompiled from Test3$.class
public final class Test3$ {
public static final Test3$ MODULE$ = new Test3$();
private static final int n = 1;
private static final int k;
static {
k = MODULE$.n();
}
public int n() {
return n;
}
public int k() {
return k;
}
private Test3$() {
}
}
这意味着这是由Scala 3中的其他一些错误(导致这个
n()
产生这样的性能影响)造成的。
这与 R- 查看具有任何 NA 的所有列名称有关 我比较了data.frame和data.table版本,发现data.table慢了10倍。这与大多数使用data.table的代码相反,后者确实比data.frame版本快得多。 预先设置: 可能是什么原因?
编辑:为什么在局部变量上这么快?(~16秒进行相同的迭代,但对函数内部的局部变量进行迭代)
为什么我的parkList变量在.each函数外是空的,而我在循环外声明了它并在循环期间填充了它的值...并且循环成功执行?
为了好玩,我决定用红宝石编码伊拉托西筛子。只是为了好玩,因为我知道有一个库函数。而且,我认为它会很快。但我发现它并不是,至少在我的ruby 1.9.3中,我的上网本速度快了好几倍,甚至在c中也没有。为什么会这样呢。 库实现: 我在红宝石: 图书馆非常慢。
问题内容: 我们正在做一些和实现Python编写的。其他人选择了Java。我们的执行时间非常不同。我使用cProfile查看我在哪里出错,但实际上一切都很好。是的,我也使用。但是我想问一个简单的问题。 此摘要在我的计算机上耗时31.40s。 此代码的Java版本在同一台计算机上花费1秒或更短的时间。我想类型检查是此代码的主要问题。但是我应该为我的项目做很多这样的操作,我认为9999 *9999的数
对于特定的任务,我需要在可变数组中进行大量快速、单独的写操作。为了检查性能,我使用了以下测试: