7 个版本

0.2.2 2021年3月18日
0.2.1 2020年6月9日
0.2.0 2020年1月25日
0.1.5 2020年1月22日

#288 in 并发

Download history 2984/week @ 2024-03-14 2435/week @ 2024-03-21 2442/week @ 2024-03-28 1662/week @ 2024-04-04 3122/week @ 2024-04-11 2191/week @ 2024-04-18 2905/week @ 2024-04-25 1972/week @ 2024-05-02 2107/week @ 2024-05-09 3053/week @ 2024-05-16 2794/week @ 2024-05-23 1779/week @ 2024-05-30 2770/week @ 2024-06-06 2291/week @ 2024-06-13 2201/week @ 2024-06-20 1099/week @ 2024-06-27

8,796 每月下载次数
用于 8 个 crates (3 直接)

Apache-2.0/MIT

58KB
1K SLoC

global_counter

文档

此 crate 实现了全局计数器,包括通用和原始的计数器,它们基于经过充分测试的同步原语,即默认的 parking_lot Mutex 和 stdlibs 的原子类型。还有更快但精度较低的计数器,具体细节请参阅文档。

使用方法

将以下依赖项添加到您的 Cargo.toml 文件中

[dependencies]
global_counter = "0.2.2"

导入时使用 #[macro_use] 注解,如下所示

#[macro_use]
extern crate global_counter;

如果您想禁用 parking_lot 的使用,并改为使用 stdlibs Mutex,请禁用默认功能

[dependencies.global_counter]
version = "0.2.2"
default-features = false

快速入门

创建一个计数器

use global_counter::generic::Counter;
use global_counter::primitive::exact::CounterI16;

// Generic
global_counter!(COUTER_NAME, CountedType, CountedType::default());

// If you feel funny, you can also create a generic global counter without a macro.
// Take a look at the implemtation of the macro, it's simply wrapping in a once_cell::sync::Lazy<...>.

// Primitive
static COUNTER_NAME : CounterI16 = CounterI16::new(0);

增加计数器的值

COUNTER_NAME.inc();

获取计数器的值

// Generic
let val_borrowed = COUNTER_NAME.get_borrowed();
// Or
let val = COUNTER_NAME.get_cloned();

// Primitive
let val = COUNTER_NAME.get();

示例 - 用于从多个线程中索引 vec 的原始计数器

#[macro_use]
extern crate global_counter;

use global_counter::primitive::exact::CounterUsize;
use std::sync::{Arc, Mutex};

fn main() {
    // This is a primitive counter. Implemented using atomics, more efficient than its generic equivalent.
    // Available for primitive integer types.
    static COUNTER: CounterUsize = CounterUsize::new(0);

    // We want to copy the 'from' arr to the 'to' arr. From multiple threads.
    // Please don't do this in actual code.
    let from = Arc::new(Mutex::new(vec![1, 5, 22, 10000, 43, -4, 39, 1, 2]));
    let to = Arc::new(Mutex::new(vec![0, 0, 0, 0, 0, 0, 0, 0, 0]));

    // 3 elements each in two other threads + 3 elements in this thread.
    // After joining those two threads, all elements will have been copied.
    let to_arc = to.clone();
    let from_arc = from.clone();
    let t1 = std::thread::spawn(move || {
        // '.inc()' increments the counter, returning the previous value.
        let indices = [COUNTER.inc(), COUNTER.inc(), COUNTER.inc()];
        for &i in indices.iter() {
            to_arc.lock().unwrap()[i] = from_arc.lock().unwrap()[i];
        }
    });

    let to_arc = to.clone();
    let from_arc = from.clone();
    let t2 = std::thread::spawn(move || {
        let indices = [COUNTER.inc(), COUNTER.inc(), COUNTER.inc()];
        for &i in indices.iter() {
            to_arc.lock().unwrap()[i] = from_arc.lock().unwrap()[i];
        }
    });

    let indices = [COUNTER.inc(), COUNTER.inc(), COUNTER.inc()];
    for &i in indices.iter() {
        to.lock().unwrap()[i] = from.lock().unwrap()[i];
    }

    t1.join().unwrap();
    t2.join().unwrap();

    assert_eq!(**to.lock().unwrap(), **from.lock().unwrap());
}

示例 - 不克隆被计数的结构体

#[macro_use]
extern crate global_counter;

use global_counter::generic::{Counter, Inc};
use std::collections::LinkedList;
use std::iter::FromIterator;

// Note how this (supposedly) doesn't implement `Clone`.
#[derive(Debug, PartialEq, Eq)]
struct CardinalityCountedList(LinkedList<()>);

// Incrementing to us means just inserting another element.
impl Inc for CardinalityCountedList {
    fn inc(&mut self) {
        self.0.push_back(());
    }
}

// Some helper methods.
impl CardinalityCountedList {
    pub fn with_cardinality(card: usize) -> Self {
        CardinalityCountedList(LinkedList::from_iter(std::iter::repeat(()).take(card)))
    }

    pub fn card(&self) -> usize {
        self.0.len()
    }
}

// We create a new global, thread-safe Counter.
// Could also do this in the main fn or wherever.
global_counter!(
    COUNTER, // Name
    CardinalityCountedList, // Type
    CardinalityCountedList::with_cardinality(0) // Initial value
);

fn main() {
    // Note how we use a borrow, but never clone this LinkedList.
    // Of course, a cloning, convenient API is also available.
    assert_eq!((*COUNTER.get_borrowed()).card(), 0);

    let t1 = std::thread::spawn(move || {
        for _ in 0..(1 << 20) {
            COUNTER.inc();
        }
    });
    let t2 = std::thread::spawn(move || {
        for _ in 0..(1 << 20) {
            COUNTER.inc();
        }
    });

    t1.join().unwrap();

    let card = (*COUNTER.get_borrowed()).card();

    // t1 finished, t2 maybe did something.
    assert!((1 << 20) <= card && card <= (2 << 20));

    t2.join().unwrap();

    // Both threads finished, the counter guarantees `Inc` was executed 2 << 20 times.
    assert_eq!((*COUNTER.get_borrowed()).card(), 2 << 20);
}

变更日志

此库仍在开发中。达到相对稳定状态后,将引入详细的变更日志。将每个版本升级视为破坏性更改。

最小 Rust 版本

从版本 0.2.2 开始,此 crate 需要 Rust 版本 1.46 或更高版本才能编译。

许可证

根据您的选择,许可协议为以下之一

贡献

除非您明确声明,否则根据Apache-2.0许可证定义,您有意提交以包含在工作中的任何贡献,将按上述方式双重授权,不附加任何额外条款或条件。

依赖项

~0.5–0.8MB
~13K SLoC