英文:
Is it worth moving `let` out of loop?
问题
在这段代码中
```rust
fn do_something_under_lock(
is_locked: &AtomicBool,
) {
loop {
let lock_acquired = is_locked
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_ok();
if lock_acquired {
// Do something
// ...
is_locked.store(false, Ordering::Release);
break;
}
}
}
将let
移到循环外,像这样
fn do_something_under_lock(
is_locked: &AtomicBool,
) {
let mut lock_acquired;
loop {
lock_acquired = is_locked
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_ok();
if lock_acquired {
// Do something
// ...
is_locked.store(false, Ordering::Release);
break;
}
}
}
会带来一些性能上的好处,当调用Drop
时会发生变化吗(根据https://doc.rust-lang.org/rust-by-example/trait/drop.html#drop
> Drop特性只有一个方法:drop,在对象超出作用域时会自动调用。Drop特性的主要用途是释放实现者实例拥有的资源。
乍一看,lock_acquired
的作用域发生了变化
),还是编译器会生成相同的代码?检查编译器输出的最佳方法是什么?
我期望编译器能理解开发者的意图是相同的,并生成相同的二进制代码。
<details>
<summary>英文:</summary>
In this code
```rust
fn do_something_under_lock(
is_locked: &AtomicBool,
) {
loop {
let lock_acquired = is_locked
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_ok();
if lock_acquired {
// Do something
// ...
is_locked.store(false, Ordering::Release);
break;
}
}
}
will moving let
outside of loop, like
fn do_something_under_lock(
is_locked: &AtomicBool,
) {
let mut lock_acquired;
loop {
lock_acquired = is_locked
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_ok();
if lock_acquired {
// Do something
// ...
is_locked.store(false, Ordering::Release);
break;
}
}
}
give some performance benefit, will it change when Drop
is called(according to https://doc.rust-lang.org/rust-by-example/trait/drop.html#drop
> The Drop trait only has one method: drop, which is called automatically when an object goes out of scope. The main use of the Drop trait is to free the resources that the implementor instance owns.
and at first glance, scope of lock_acquired
changed
), or will compiler produce same code anyway? What is the best way to check compiler output?
I expect compiler to understand that developer intent is the same and produce the same binary
答案1
得分: 4
第一段代码在理论上每次都为一个新的布尔值在堆栈上分配空间,并在循环体结束时将其删除。第二段代码在函数结束时分配一次新的布尔值然后将其删除。
然而,编译器几乎肯定会将它们编译成相同的指令,如果使用堆栈,则使用相同的堆栈位置,但更可能使用寄存器来存储布尔值。
第一段代码也更容易阅读,因为清楚地表明布尔值的值仅在循环体的持续时间内设置,不会影响后续的迭代。
在性能方面更值得关注的是,此代码将在另一个线程持有锁时自旋在一个紧密的循环中,这可能会影响另一个线程解锁的速度。我建议使用现有的提供锁定功能的包(std::sync
或parking_lot
)。
英文:
In theory the first code allocates space on the stack for a new boolean each time and removes it at the end of the loop body. The second code allocates a new boolean once and removes it at the end of the function.
However, the compiler will almost certainly compile these to the same instructions, using the same location on the stack if it uses the stack, but more likely using a register for the boolean.
The first code is also easier for a human to read, since it is clear that the value of the boolean is only set for the duration of the loop body and does not affect subsequent iterations.
Of more concern for performance, this code will spin in a tight loop while another thread has the lock, which may affect the speed at which the other thread gets to unlock. I'd recommend using existing crates that provide locking (std::sync
or parking_lot
).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论