小编at5*_*321的帖子

为什么 Rust 链接器在增量构建时没有更快?

我是 Rust 的新手,我试图理解为什么 Rust 不能构建得更快。我专门讨论最常见的情况,我对我的一个源文件做了一个小改动,然后我需要等待几秒钟cargo build才能完成它的工作。即使我的应用程序代码非常小,例如,如果我添加对 MySQL 和 Rocket 的依赖项,这两个 crate 也会附带它们自己的依赖项,显然这就是构建过程显着变慢的原因。显然,“慢”的意思是非常主观的,但是如果我需要等待 5-10 秒才能完成一天一百次的事情,我想知道为什么需要这样,我是否遗漏了什么.

在我看来,Cargo 并没有浪费太多时间来检查它是否需要重新编译这 200-300 个(子)依赖项中的任何一个,但需要这么长时间的是链接器。我试图了解链接器无法以某种方式优化该过程是否存在客观原因。例如,是否有可能以某种方式将整个 MySQL 和 Rocket 依赖项构建和缓存到两个更大的库中,并避免每次都执行所有这些工作?即使以二进制文件中的一些代码重复为代价。

顺便说一句,我尝试了 LLD 链接器(我使用的是 Ubuntu),它在一定程度上加快了速度,但它似乎仍然受到大量子依赖项的严重影响。

linker linkage rust rust-cargo

5
推荐指数
1
解决办法
176
查看次数

使用什么链接器来构建 Rust 二进制文件?

如果我只有二进制可执行文件,我如何知道它是用哪个链接器构建的?

linker rust

5
推荐指数
1
解决办法
650
查看次数

Serde 根据“全局”运行时条件跳过字段序列化

根据某些运行时条件,我想序列化或不序列化字段。该条件适用于整个序列化,与字段值本身无关。因此,如果我理解正确的话,我就不能使用skip_serializing_if()它,除非我使用某种全局状态,但这更像是一个常量,而不是一个“条件”。

例如,假设条件取决于请求文件的客户端。有些客户需要拥有该字段,而其他客户则不需要。

如果条件表示序列化,即使字段的值为序列化(即显式创建一个具有输出 JSON 中的值的None属性),也请执行序列化操作。null

实现这一目标的最简单、最干净的方法是什么?

rust serde

5
推荐指数
1
解决办法
1033
查看次数

为什么我不应该使用增量构建来发布二进制文件?

我注意到,随着我的项目的增长,发布编译/构建时间变得比我预期(和希望)更快。我决定研究一下可以采取哪些措施来提高编译速度。我不是在谈论初始构建时间,它涉及依赖项的编译并且很大程度上无关紧要。

似乎有很大帮助的一件事是incremental = true配置文件设置。在我的项目中,它似乎将 4 个以上内核的构建时间缩短了约 40%。使用更少的核心,收益会更大,因为构建incremental = true似乎没有使用(太多)并行化。使用默认值(对于--release),incremental = false与 4 个以上内核相比,单个内核的构建时间要慢 3-4 倍。

incremental = true避免用于生产构建的原因是什么?我没有看到缓存对象的二进制大小或存储大小有任何(显着)增加。我在某处读到增量构建可能会导致构建的二进制文件的性能稍差。这是需要考虑的唯一原因还是还有其他原因,例如稳定性等?

我知道这可能会有所不同,但是是否有任何数据可以说明对实际应用程序的性能影响有多大?

compilation rust

5
推荐指数
1
解决办法
1105
查看次数

仅使用非 None 值初始化 Vec

如果我有这样的变量:

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())等。

rust

5
推荐指数
1
解决办法
1056
查看次数

从字符串中删除前导零

从字符串中删除所有前导零的最简单方法是什么?

这是我想出的东西:

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)

就简洁性和/或性能而言,是否有更好的东西?

rust

4
推荐指数
1
解决办法
1136
查看次数

具有原子读写功能的 Mutex&lt;bool&gt;

我需要有一个可由多个线程访问的全局布尔标志。

这是我需要的示例:

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]>也可以使用,并且理论上应该更快,尽管在我的特殊情况下,速度优势将不明显。

concurrency mutex rust

4
推荐指数
2
解决办法
1395
查看次数

使用 .unwrap() 应该被视为不好的做法吗?

看到这个问题下的评论,让我想知道 - 使用是否应该unwrap()被视为不好的做法?

在我看来,有时打开包装是有意义的。至少在这两种情况下:

  1. 我们知道一个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)
  1. 如果我们开发一个简单的短期工具,无论哪种方式都会以错误结束,依靠恐慌而不是“适当的”错误处理(使用Result?等)可以或多或少地简化代码。

显然,有时依赖unwrap()可能弊大于利,所以我是否应该始终避免使用对我来说并不是很明显unwrap()?如果没有的话什么时候可以使用unwrap()

error-handling rust

2
推荐指数
1
解决办法
1444
查看次数

使用 Option 中的 0 或 1 个元素创建向量

有没有更短、更简单的方法来实现这一目标:

let o: Option<i32> = ...;
let ve: Vec<i32> = match o {
    None => vec![],
    Some(n) => vec![n],
};
Run Code Online (Sandbox Code Playgroud)

rust

2
推荐指数
2
解决办法
145
查看次数

从 Vector 字段创建 HashMap 的最有效方法

假设我们有一个结构向量:

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)

这肯定不是最高效的解决方案,因为它创建了一个临时的元组向量,但正如我所说,在这种情况下,我最关心的是方便性和简洁性。那么,还有比这更简单的事情吗?

rust

1
推荐指数
1
解决办法
51
查看次数

将通用参数转换为特定类型

如果我有两个结构:

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 中做类似的事情?我知道我可以将一些特定于类型的逻辑放入特征中,但我特别要求一种更简单、更直接的方法。

generics casting rust

1
推荐指数
1
解决办法
373
查看次数