[英]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,正如我所怀疑的,
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第二轮
--- 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.