简体   繁体   English

什么更高效:直接设置值还是先检查值是否更改然后再设置?

[英]What is more performant: directly setting a value or first check if the value changed and then set it?

Option 1:选项1:

List<Object> listObjects = new ArrayList<>();
for(Object object : listObjects){
  object.setValue1("new value");
}

Option 2:选项 2:

List<Object> listObjects = new ArrayList<>();
for(Object object : listObjects){
  if(!object.getValue1().equals("new value"))
     object.setValue1("new value");
}

Which of the above options is more performant in terms of cpu and memory usage?以上哪个选项在 CPU 和内存使用方面的性能更高?

Additional context: Let's imagine the objects list is pretty big and we loop through it every 5 seconds.附加上下文:假设对象列表非常大,我们每 5 秒循环一次。

我的投票将是选项 1:它更短(忽略 setValue2 调用),如果它是一个对象,则赋值只是加载和存储一个指针,而如果对象非常大,则equal比较可能需要很长时间。

Here is the test I did (openJDK 11).这是我所做的测试(openJDK 11)。 As I suspected,正如我所怀疑的,

  1. "testSetValueNoCheck" and "testSetValueWithCheckUsingStatic" and "testSetValueWithCheckUsingLiteral" are almost same which means you can ignore the difference. “testSetValueNoCheck”和“testSetValueWithCheckUsingStatic”和“testSetValueWithCheckUsingLiteral”几乎相同,这意味着您可以忽略差异。
  2. The interesting thing is "testSetValueWithCheckUsingStatic\\testSetValueWithCheckUsingLiteral second time " time is always half the time of #1.有趣的是“第二次testSetValueWithCheckUsingStatic\\testSetValueWithCheckUsingLiteral”的时间总是#1 的一半 I believe it is because how equals is implemented in Java for String - the functions that actual do work "StringLatin1.equals" and "StringUTF16.equals" are annotated "@HotSpotIntrinsicCandidate" which may or may not happen.我相信这是因为在 Java 中如何为 String 实现 equals - 实际工作的函数“StringLatin1.equals”和“StringUTF16.equals”被注释为“@HotSpotIntrinsicCandidate”,这可能会也可能不会发生。 That also means if data is not String , results will differ in scenarios above based on how equals is implemented.这也意味着如果 data 不是String ,根据 equals 的实现方式,结果将在上述场景中有所不同。

The "second time" case is relevant based you what you wrote: “第二次”案例与您所写的内容相关:

Additional context: Let's imagine the objects list is pretty big and we loop through it every 5 seconds.附加上下文:假设对象列表非常大,我们每 5 秒循环一次。

So, in general I do agree with advice in comments - worry about performance when you need to.因此,总的来说,我确实同意评论中的建议 - 在需要时担心性能。 Personally for me, the time is every time I finish the module and have unit tests, do performance testing.就我个人而言,时间是每次我完成模块并进行单元测试,进行性能测试。 It takes day (or even less if you have automation), but I have never found it to be counter productive.这需要一天(如果你有自动化,甚至更少),但我从来没有发现它会适得其反。

Output:输出:

testSetValueNoCheck: 39.9644 testSetValueNoCheck:39.9644

testSetValueWithCheckUsingStatic: 40.4051 testSetValueWithCheckUsingStatic:40.4051

testSetValueWithCheckUsingStatic second time: 13.7888 testSetValueWithCheckUsingStatic 第二次:13.7888

testSetValueWithCheckUsingLiteral: 33.6455 testSetValueWithCheckUsingLiteral: 33.6455

testSetValueWithCheckUsingLiteral second time: 18.5136 testSetValueWithCheckUsingLiteral 第二次:18.5136

Code:代码:

    class SetValueTest {
    class MyObject {
        private String _val;
        MyObject(final String val) {
            _val = val;
        }
        
        String getValue() {
            return _val;
        }
        
        void setValue(final String val) {
            _val = val;
        }
        
    }
    
    ArrayList<MyObject> getData() {
        final ArrayList<MyObject> data = new ArrayList<>();
        for(int i = 0; i < 1000000; ++i) {
            data.add(new MyObject(String.format("%d", i)));
        }
        return data;
        
    }
    
    SetValueTest() throws InterruptedException {
        long start = 0L, end = 0L; 
        
        final ArrayList<MyObject> data1 = getData();
        
        start = System.nanoTime();
        testSetValueNoCheck(data1);
        end = System.nanoTime();
        System.out.println("testSetValueNoCheck: " + (end - start) / 1e6);
        
        final ArrayList<MyObject> data2 = getData();
        
        Thread.currentThread().sleep(1000);
        
        start = System.nanoTime();
        testSetValueWithCheckUsingStatic(data2);
        end = System.nanoTime();
        System.out.println("testSetValueWithCheckUsingStatic: " + (end - start) / 1e6);
        
        start = System.nanoTime();
        testSetValueWithCheckUsingStatic(data2);
        end = System.nanoTime();
        System.out.println("testSetValueWithCheckUsingStatic second time: " + (end - start) / 1e6);
        
        
        final ArrayList<MyObject> data3 = getData();
        
        Thread.currentThread().sleep(1000);         
        
        start = System.nanoTime();
        testSetValueWithCheckUsingLiteral(data3);
        end = System.nanoTime();
        System.out.println("testSetValueWithCheckUsingLiteral: " + (end - start) / 1e6);
        
        start = System.nanoTime();
        testSetValueWithCheckUsingLiteral(data3);
        end = System.nanoTime();
        System.out.println("testSetValueWithCheckUsingLiteral second time: " + (end - start) / 1e6);
        
    }
    
    void testSetValueNoCheck(List<MyObject> objs) {
        for (MyObject obj : objs) {
            obj.setValue(NewValue);
        }
    }
    
    void testSetValueWithCheckUsingLiteral(List<MyObject> objs) {
        for (MyObject obj : objs) {
            if (!obj.getValue().equals("new Value")) {
                obj.setValue("new Value");
            }
        }
    }       
    
    static final String NewValue = "new Value";
    
    void testSetValueWithCheckUsingStatic(List<MyObject> objs) {
        for (MyObject obj : objs) {
            if (!obj.getValue().equals(NewValue)) {
                obj.setValue(NewValue);
            }
        }
    }
    
}

SECOND ROUND第二轮

  • Changes:变化:

--- changed the class so that and ran once per class run so that garbage collection\\memory would not interfere with readings --- 更改了类,以便每个类运行一次,以便垃圾收集\\内存不会干扰读数

--- sleep changed to 5 seconds to simulate actual scenario --- sleep 改为 5 秒以模拟实际场景

--- ran each test 10 times with average as following: --- 每个测试运行 10 次,平均值如下:

testSetValueWithCheckUsingStatic: Average First Time: 27.728210 Second Time: 10.979410 testSetValueWithCheckUsingStatic:平均第一次:27.728210 第二次:10.979410

testSetValueWithCheckUsingLiteral: Average First Time: 23.161670 Second Time: 12.896330 testSetValueWithCheckUsingLiteral:平均第一次:23.161670 第二次:12.896330

testSetValueNoCheckStatic: Average First Time: 20.294100 Second Time: 21.679260 testSetValueNoCheckStatic:平均第一次:20.294100 第二次:21.679260

testSetValueNoCheckLiteral: Average First Time: 29.137620 Second Time: 19.812040 testSetValueNoCheckLiteral:平均第一次:29.137620 第二次:19.812040

    static class SetValueTest {
    class MyObject {
        private String _val;
        MyObject(final String val) {
            _val = val;
        }
        
        String getValue() {
            return _val;
        }
        
        void setValue(final String val) {
            _val = val;
        }
        
    }
    
    ArrayList<MyObject> getData() {
        
        final ArrayList<MyObject> data = new ArrayList<>();
        for(int i = 0; i < 1000000; ++i) {
            data.add(new MyObject(String.format("%d", i)));
        }
        return data;
        
    }
    
    private final static int SleepTime = 5000;
    private static final String NewValue = "new Value";
    
    SetValueTest(final int test) throws InterruptedException {

        final ArrayList<Double> firstTimes = new ArrayList<>();
        final ArrayList<Double> secondTimes = new ArrayList<>();
        String testName = "";
        final int times = 10;
        for (int i = 0; i < times; ++i) {
            double firstTime = 0, secondTime = 0;
            final ArrayList<MyObject> data = getData();
            switch (test) {
            case 1:
                testName = "testSetValueWithCheckUsingStatic";
                firstTime = testSetValueWithCheckUsingStatic(data);
                secondTime = testSetValueWithCheckUsingStatic(data);
                break;
            case 2:
                testName = "testSetValueWithCheckUsingLiteral";
                firstTime = testSetValueWithCheckUsingLiteral(data);
                secondTime = testSetValueWithCheckUsingLiteral(data);
                break;
            case 3:                 
                testName = "testSetValueNoCheckStatic";
                firstTime = testSetValueNoCheckStatic(data);
                secondTime = testSetValueNoCheckStatic(data);
                break;
            case 4:                 
                testName = "testSetValueNoCheckLiteral";
                firstTime = testSetValueNoCheckLiteral(data);
                secondTime = testSetValueNoCheckLiteral(data);
                break;
            }
            firstTimes.add(firstTime);
            secondTimes.add(secondTime);
        }
        
        double firstTimeTotal = 0, secondTimeTotal = 0;
        System.out.println("Test: " + testName);
        for (int time = 0; time < times; ++time) {
            System.out.println(String.format("First Time: %f Second Time: %f", firstTimes.get(time), secondTimes.get(time)));
            firstTimeTotal += firstTimes.get(time);
            secondTimeTotal += secondTimes.get(time);
        }
        System.out.println(String.format("Average First Time: %f Second Time: %f", firstTimeTotal / times, secondTimeTotal / times));
        
        
    }
    
    double toMilliseconds(final long start, final long end) {
        return ((end - start) / 1e6);
    }
    
    double testSetValueNoCheckStatic(List<MyObject> objs) throws InterruptedException {
        
        long start = 0L, end = 0L; 
        start = System.nanoTime();
        for (MyObject obj : objs) {
            obj.setValue(NewValue);
        }
        end = System.nanoTime();
        Thread.currentThread().sleep(SleepTime);
        return toMilliseconds(start, end);
        
    }
    
    double testSetValueNoCheckLiteral(List<MyObject> objs) throws InterruptedException {
        
        long start = 0L, end = 0L; 
        start = System.nanoTime();
        for (MyObject obj : objs) {
            obj.setValue("new Value");
        }
        end = System.nanoTime();
        Thread.currentThread().sleep(SleepTime);
        return toMilliseconds(start, end);          
        
    }
    
    
    double testSetValueWithCheckUsingLiteral(List<MyObject> objs) throws InterruptedException {
        long start = 0L, end = 0L; 
        start = System.nanoTime();
        
        for (MyObject obj : objs) {
            if (!obj.getValue().equals("new Value")) {
                obj.setValue("new Value");
            }
        }
        end = System.nanoTime();
        Thread.currentThread().sleep(SleepTime);
        return toMilliseconds(start, end);          
    }       

    
    double testSetValueWithCheckUsingStatic(List<MyObject> objs) throws InterruptedException {
        long start = 0L, end = 0L; 
        start = System.nanoTime();
        
        for (MyObject obj : objs) {
            if (!obj.getValue().equals(NewValue)) {
                obj.setValue(NewValue);
            }
        }
        end = System.nanoTime();
        Thread.currentThread().sleep(SleepTime);
        return toMilliseconds(start, end);          
        
    }
    
}

Actual output:实际输出:

Test: testSetValueWithCheckUsingStatic First Time: 42.110700 Second Time: 21.398500 First Time: 37.834800 Second Time: 10.124700 First Time: 18.263600 Second Time: 8.967400 First Time: 16.655500 Second Time: 7.146000 First Time: 18.729900 Second Time: 8.753300 First Time: 17.513100 Second Time: 14.622800 First Time: 24.000300 Second Time: 9.534700 First Time: 61.357000 Second Time: 11.677700 First Time: 26.832500 Second Time: 10.160400 First Time: 13.984700 Second Time: 7.408600 Average First Time: 27.728210 Second Time: 10.979410测试:testSetValueWithCheckUsingStatic第一次:42.110700第二次:21.398500第一次:37.834800第二次:10.124700第一次:18.263600第二回:8.967400第一次:16.655500第二回:7.146000第一次:18.729900第二回:8.753300第一次:17.513100第二次: 14.622800 第一次:24.000300 第二次:9.534700 第一次:61.357000 第二次:11.677700 第一次:26.832500 第二次:10.160400 第一次:13.07 第二次:10.97 1986

Test: testSetValueWithCheckUsingLiteral First Time: 54.417700 Second Time: 22.161600 First Time: 20.950000 Second Time: 14.621500 First Time: 31.008100 Second Time: 13.631600 First Time: 14.052500 Second Time: 10.490900 First Time: 20.904800 Second Time: 8.727700 First Time: 13.338300 Second Time: 13.519100 First Time: 18.740800 Second Time: 13.030500 First Time: 14.959100 Second Time: 15.166100 First Time: 25.593000 Second Time: 8.041300 First Time: 17.652400 Second Time: 9.573000 Average First Time: 23.161670 Second Time: 12.896330测试:testSetValueWithCheckUsingLiteral第一次:54.417700第二次:22.161600第一次:20.950000第二次:14.621500第一次:31.008100第二次:13.631600第一次:14.052500第二次:10.490900第一次:20.904800第二回:8.727700第一次:13.338300第二次: 13.519100 第一次:18.740800 第二次:13.030500 第一次:14.959100 第二次:15.166100 第一次:25.593000 第二次:8.041300 第一次:17.05.0736 第二次:17.057362

Test: testSetValueNoCheckStatic First Time: 34.467700 Second Time: 33.953200 First Time: 15.307500 Second Time: 14.245300 First Time: 34.042700 Second Time: 31.824600 First Time: 11.989300 Second Time: 12.266800 First Time: 15.556500 Second Time: 24.501000 First Time: 12.314800 Second Time: 16.539600 First Time: 14.333300 Second Time: 14.500300 First Time: 11.876900 Second Time: 21.599900 First Time: 39.020400 Second Time: 31.754800 First Time: 14.031900 Second Time: 15.607100 Average First Time: 20.294100 Second Time: 21.679260测试:testSetValueNoCheckStatic第一次:34.467700第二次:33.953200第一次:15.307500第二次:14.245300第一次:34.042700第二次:31.824600第一次:11.989300第二次:12.266800第一次:15.556500第二次:24.501000第一次:12.314800第二次: 16.539600 第一次:14.333300 第二次:14.500300 第一次:11.876900 第二次:21.599900 第一次:39.020400 第二次:31.754800 第一次:105.206 次:105.206 次:105.206 次:105.206

Test: testSetValueNoCheckLiteral First Time: 49.325300 Second Time: 27.528700 First Time: 26.355500 Second Time: 27.800100 First Time: 23.862700 Second Time: 15.576400 First Time: 25.133000 Second Time: 16.290500 First Time: 28.379000 Second Time: 18.192400 First Time: 83.170600 Second Time: 18.183800 First Time: 13.570100 Second Time: 14.341100 First Time: 11.793900 Second Time: 13.960000 First Time: 16.238900 Second Time: 30.233200 First Time: 13.547200 Second Time: 16.014200 Average First Time: 29.137620 Second Time: 19.812040测试:testSetValueNoCheckLiteral第一次:49.325300第二次:27.528700第一次:26.355500第二次:27.800100第一次:23.862700第二次:15.576400第一次:25.133000第二次:16.290500第一次:28.379000第二次:18.192400第一次:83.170600第二次: 18.183800 第一次:13.570100 第二次:14.341100 第一次:11.793900 第二次:13.960000 第一次:16.238900 第二次:30.233200 第一次:13.204 次:23.204 107 次:13.204

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 检查值的变化是否超过 10^-3? - Check if a value hasn't changed more than 10^-3? 性能更好的equal或instanceof是什么? - what is more performant equal or instanceof? 我是否应该将我的setter方法作为“set”的前缀,如果它不仅仅是设置一个值? - Should I prefix my setter method with “set” if it does something more than just setting a value? 额外的&#39;if checks&#39;如果已经设置了值 - 什么更快,什么使用更多资源? - Additional 'if checks' if the value is already set up - what is faster, what uses more resources? 检查 Vector 的值是否在 Set 中<String> - Check if a value of a Vector are in Set<String> 检查是否在JSP中设置了特定值 - Check particular value is set or not in JSP 什么是检查字符串是否是多个枚举类型的值的一种很好的可扩展方法 - What is a good extensible way to check if a string is a value of more than one Enum Type MySQL + Android检查是否存在更多值 - MySQL + Android check if more value exists 检查数组中是否包含值的更有效方法? - More efficient way to check if a value is included in an array? 可以采取哪些步骤来优化tibco JMS以提高性能? - What steps can be taken to optimize tibco JMS to be more performant?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM