我是 Rust 的新手,我试图理解为什么 Rust 不能构建得更快。我专门讨论最常见的情况,我对我的一个源文件做了一个小改动,然后我需要等待几秒钟cargo build才能完成它的工作。即使我的应用程序代码非常小,例如,如果我添加对 MySQL 和 Rocket 的依赖项,这两个 crate 也会附带它们自己的依赖项,显然这就是构建过程显着变慢的原因。显然,“慢”的意思是非常主观的,但是如果我需要等待 5-10 秒才能完成一天一百次的事情,我想知道为什么需要这样,我是否遗漏了什么.
在我看来,Cargo 并没有浪费太多时间来检查它是否需要重新编译这 200-300 个(子)依赖项中的任何一个,但需要这么长时间的是链接器。我试图了解链接器无法以某种方式优化该过程是否存在客观原因。例如,是否有可能以某种方式将整个 MySQL 和 Rocket 依赖项构建和缓存到两个更大的库中,并避免每次都执行所有这些工作?即使以二进制文件中的一些代码重复为代价。
顺便说一句,我尝试了 LLD 链接器(我使用的是 Ubuntu),它在一定程度上加快了速度,但它似乎仍然受到大量子依赖项的严重影响。
根据某些运行时条件,我想序列化或不序列化字段。该条件适用于整个序列化,与字段值本身无关。因此,如果我理解正确的话,我就不能使用skip_serializing_if()它,除非我使用某种全局状态,但这更像是一个常量,而不是一个“条件”。
例如,假设条件取决于请求文件的客户端。有些客户需要拥有该字段,而其他客户则不需要。
如果条件表示序列化,即使字段的值为序列化(即显式创建一个具有输出 JSON 中的值的None属性),也请执行序列化操作。null
实现这一目标的最简单、最干净的方法是什么?
我注意到,随着我的项目的增长,发布编译/构建时间变得比我预期(和希望)更快。我决定研究一下可以采取哪些措施来提高编译速度。我不是在谈论初始构建时间,它涉及依赖项的编译并且很大程度上无关紧要。
似乎有很大帮助的一件事是incremental = true配置文件设置。在我的项目中,它似乎将 4 个以上内核的构建时间缩短了约 40%。使用更少的核心,收益会更大,因为构建incremental = true似乎没有使用(太多)并行化。使用默认值(对于--release),incremental = false与 4 个以上内核相比,单个内核的构建时间要慢 3-4 倍。
incremental = true避免用于生产构建的原因是什么?我没有看到缓存对象的二进制大小或存储大小有任何(显着)增加。我在某处读到增量构建可能会导致构建的二进制文件的性能稍差。这是需要考虑的唯一原因还是还有其他原因,例如稳定性等?
我知道这可能会有所不同,但是是否有任何数据可以说明对实际应用程序的性能影响有多大?
如果我有这样的变量:
let a: u32 = ...;
let b: Option<u32> = ...;
let c: u32 = ...;
Run Code Online (Sandbox Code Playgroud)
,制作这些值的向量的最短方法是什么,以便仅在 b 为 时才包含 b Some?
换句话说,有没有比这更简单的事情:
let v = match b {
None => vec![a, c],
Some(x) => vec![a, x, c],
};
Run Code Online (Sandbox Code Playgroud)
PS 我更喜欢一个不需要多次使用变量的解决方案。考虑这个例子:
let some_person: String = ...;
let best_man: Option<String> = ...;
let a_third_person: &str = ...;
let another_opt: Option<String> = ...;
...
Run Code Online (Sandbox Code Playgroud)
可以看出,我们可能必须使用更长的变量名、多个Option( None)、表达式(如a_third_person.to_string())等。
从字符串中删除所有前导零的最简单方法是什么?
这是我想出的东西:
let mut chars = original_str.chars();
let mut res = chars.as_str();
while chars.next() == Some('0') {
res = chars.as_str();
}
Run Code Online (Sandbox Code Playgroud)
就简洁性和/或性能而言,是否有更好的东西?
我需要有一个可由多个线程访问的全局布尔标志。
这是我需要的示例:
static GLOBAL_FLAG: SyncLazy<Mutex<bool>> = SyncLazy::new(|| {
Mutex::new(false)
});
fn set_flag_to_true() { // can be called by 2+ threads concurrently
*GLOBAL_FLAG.lock().unwrap() = true;
}
fn get_flag_and_set_to_true() -> bool { // only one thread is calling this function
let v = *GLOBAL_FLAG.lock().unwrap(); // Obtain current flag value
*GLOBAL_FLAG.lock().unwrap() = true; // Always set the flag to true
v // Return the previous value
}
Run Code Online (Sandbox Code Playgroud)
实施get_flag_and_set_to_true()感觉不太正确。我想最好只锁一次。最好的方法是什么?
顺便说一句,我想Arc<[AtomicBool]>也可以使用,并且理论上应该更快,尽管在我的特殊情况下,速度优势将不明显。
看到这个问题下的评论,让我想知道 - 使用是否应该unwrap()被视为不好的做法?
在我看来,有时打开包装是有意义的。至少在这两种情况下:
Option值不能是None,因为我们已经在代码的前面处理过这种情况。一个例子:if o.is_none() {
// do some stuff here...
return ...;
}
// ...
o.unwrap() // <--- Here I do NOT expect a None
Run Code Online (Sandbox Code Playgroud)
Result、?等)可以或多或少地简化代码。显然,有时依赖unwrap()可能弊大于利,所以我是否应该始终避免使用对我来说并不是很明显unwrap()?如果没有的话什么时候可以使用unwrap()?
有没有更短、更简单的方法来实现这一目标:
let o: Option<i32> = ...;
let ve: Vec<i32> = match o {
None => vec![],
Some(n) => vec![n],
};
Run Code Online (Sandbox Code Playgroud) 假设我们有一个结构向量:
struct Item {
id: u32,
name: String,
// ...
}
let mut items: Vec<Item> = vec!(
Item { id: 54, name: "Foo".into() },
Item { id: 87, name: "Bar".into() });
Run Code Online (Sandbox Code Playgroud)
创建如下所示的 HashMap 的最有效方法是什么:
{87: "Bar", 54: "Foo"}
Run Code Online (Sandbox Code Playgroud)
?
通过“高效”,在这种情况下,我主要是指“不那么冗长”。为什么?因为我觉得在大多数实际情况下,轻微的性能损失并不重要。但当它确实重要时,人们总是可以诉诸于HashMap::with_capacity()一个简单的循环,例如。尽管如此,在其他条件相同的情况下,我当然更喜欢速度更快且使用更少内存的解决方案。
我能想到的最简单的事情是:
let temp_tuples = items.iter().map(|x| (x.id, x.name.clone())).collect::<Vec<_>>();
let map_names_by_id: HashMap<_, _> = temp_tuples.into_iter().collect();
Run Code Online (Sandbox Code Playgroud)
这肯定不是最高效的解决方案,因为它创建了一个临时的元组向量,但正如我所说,在这种情况下,我最关心的是方便性和简洁性。那么,还有比这更简单的事情吗?
如果我有两个结构:
struct A {...}
struct B {...}
Run Code Online (Sandbox Code Playgroud)
fn f<T>(param: T)以及我通过传递对Aor的引用来调用的通用函数B,该函数中是否有一种方法可以具有类似这样的内容(伪代码):
if param is A {
// do something with "param as A", like this:
let a: A = (A) param;
// ...
}
Run Code Online (Sandbox Code Playgroud)
在 Java、C# 等语言中,我会简单地检查一个对象是否是 的实例A,如果是,则将其强制转换A为上面的示例。我怎样才能在 Rust 中做类似的事情?我知道我可以将一些特定于类型的逻辑放入特征中,但我特别要求一种更简单、更直接的方法。
rust ×11
linker ×2
casting ×1
compilation ×1
concurrency ×1
generics ×1
linkage ×1
mutex ×1
rust-cargo ×1
serde ×1