0

我有一个从第三方库获取数据的时间敏感应用程序。将它们的对象包装到更适合我的应用程序的接口中会对性能造成什么影响?

注意:我在这里发布答案(问答风格),但如果有错误,请纠正我!

4

2 回答 2

1

间接有一些开销,但很难衡量。OP 的基准测试每次迭代大约需要 4 ns,而我的需要大约 1 ns(对于最快的实验)。这意味着他们主要测量 , 的开销ArrayListIterator并且cycle可能与虚拟调用开销一起测量。

要测量的开销是如此之小,以至于您需要使用数组并添加内部循环或使用掩码来访问它们。

我的基准测试结果表明,使用接口和间接都存在可测量的开销。这个开销可能在 20% 到 50% 之间,看起来很多。然而,重要的部分是 20-50 % 它只是特制基准测试的一小部分,除了执行代码之外什么都不做。在任何现实的片段代码中,相对开销都会低十、一百或千倍。

因此,除非您正在设计一个高性能库来执行一些非常基本且快速的操作,否则请忘记它。随意使用间接和接口,专注于好的设计。即使性能很重要,您可能还有其他地方可以获得更多收益。

包装基准

于 2013-10-04T06:57:47.080 回答
0

在尝试了几个月的课程后,今天我决定进行测试。似乎它不会增加太多开销。以下是结果 - 实际上并不是那么一致,这是一个实际上已经展开的结果是 SLOWER:

 0% Scenario{vm=java, trial=0, benchmark=Unwrapped} 3.96 ns; ?=0.02 ns @ 3 trials
33% Scenario{vm=java, trial=0, benchmark=Copy} 3.93 ns; ?=0.01 ns @ 3 trials
67% Scenario{vm=java, trial=0, benchmark=Backing} 3.94 ns; ?=0.01 ns @ 3 trials

benchmark   ns linear runtime
Unwrapped 3.96 ==============================
     Copy 3.93 =============================
  Backing 3.94 =============================

vm: java
trial: 0

源代码(Caliper 0.5-rc1,Guava 2.0+):

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;
import com.google.common.collect.Iterables;

public class WrapperTest {
    public static class Unwrapped {
        private int inner;

        public Unwrapped(int inner) {
            this.inner = inner;
        }

        public int getInner() {
            return inner;
        }
    }

    public static interface Outer {
        public int getOuter();
    }

    public static class CopyOuter implements Outer {
        private int outer;

        public CopyOuter(int outer) {
            this.outer = outer;
        }

        public int getOuter() {
            return outer;
        }
    }

    public static class BackingOuter implements Outer {
        private Unwrapped inner;

        public BackingOuter(Unwrapped inner) {
            this.inner = inner;
        }

        public int getOuter() {
            return inner.getInner();
        }
    }

    public static class TestBenchmark extends SimpleBenchmark {
        private Iterable<Unwrapped> cycle;

        @Override
        protected void setUp() {
            List<Unwrapped> backing = new ArrayList<Unwrapped>(16384);
            Random r = new Random();
            for(int i = 0; i < 16384; i++) {
                backing.add(new Unwrapped(Math.abs(r.nextInt())));
            }
            cycle = Iterables.cycle(backing);
        }

        public long timeUnwrapped(int reps) {
            long total = 0;
            Iterator<Unwrapped> iter = cycle.iterator();
            for(int i = 0; i < reps; i++) {
                total += iter.next().getInner();
            }
            return total;
        }

        public long timeCopy(int reps) {
            long total = 0;
            Iterator<Unwrapped> iter = cycle.iterator();
            for(int i = 0; i < reps; i++) {
                total += new CopyOuter(iter.next().getInner()).getOuter();
            }
            return total;
        }

        public long timeBacking(int reps) {
            long total = 0;
            Iterator<Unwrapped> iter = cycle.iterator();
            for(int i = 0; i < reps; i++) {
                total += new BackingOuter(iter.next()).getOuter();
            }
            return total;
        }
    }

    public static void main(String[] args) {
        Runner.main(TestBenchmark.class, new String[0]);
    }
}
于 2013-09-29T22:59:53.063 回答