实验要求

  • 实现分支:ch1
  • 完成实验指导书中的内容并在裸机上实现 hello world 输出。
  • 实现彩色输出宏(只要求可以彩色输出,不要求 log 等级控制,不要求多种颜色)
  • 隐形要求

    可以关闭内核所有输出。从 lab2 开始要求关闭内核所有输出(如果实现了 log 等级控制,那么这一点自然就实现了)。
  • 利用彩色输出宏输出 os 内存空间布局

    输出 .text.data.rodata.bss 各段位置,输出等级为 INFO

ANSI 转义字符

ANSI转义序列

  1. echo -e "\x1b[31mhello world\x1b[0m"

参考资源

官方给出如下资源:对于 Rust, 可以使用 crate log ,推荐参考 rCore

crate log 的应用

打开提供的参考链接,可以了解到应用log这个特质的方式,看Use这一节,

The basic use of the log crate is through the five logging macros: error!warn!info!debug! and trace! where error! represents the highest-priority log messages and trace! the lowest. The log messages are filtered by configuring the log level to exclude messages with a lower priority. Each of these macros accept format strings similarly to println!.

In libraries里可以看到,我们如果要使用log,则需要使用crate log,

Libraries should link only to the log crate, and use the provided macros to log whatever information will be useful to downstream consumers.

例子

参考Examples,创建一个新的工程来测试它,在/homework/homework-1-log下用cargo new test_log创建一个测试工程,在test_log/src下,万万没想到,这个例子竟然成为了最猛的一集,完美展示了不懂一门语言硬学导致的问题.

RustCrate log的例子中为:

  1. use log::{info, warn};
  2. pub fn shave_the_yak(yak: &mut Yak) {
  3. info!(target: "yak_events", "Commencing yak shaving for {:?}", yak);
  4. loop {
  5. match find_a_razor() {
  6. Ok(razor) => {
  7. info!("Razor located: {}", razor);
  8. yak.shave(razor);
  9. break;
  10. }
  11. Err(err) => {
  12. warn!("Unable to locate a razor: {}, retrying", err);
  13. }
  14. }
  15. }
  16. }

但是这一段是伪代码,运行的时候是会报错的:

  1. Compiling test_log v0.1.0 (/home/winddevil/workspace/homework/homework-1-log/test_log)
  2. error[E0432]: unresolved import `log`
  3. --> src/main.rs:2:5
  4. |
  5. 2 | use log::{info, warn};
  6. | ^^^ use of undeclared crate or module `log`
  7. error[E0412]: cannot find type `Yak` in this scope
  8. --> src/main.rs:3:32
  9. |
  10. 3 | pub fn shave_the_yak(yak: &mut Yak)
  11. | ^^^ not found in this scope
  12. error[E0425]: cannot find function `find_a_razor` in this scope
  13. --> src/main.rs:9:15
  14. |
  15. 9 | match find_a_razor()
  16. | ^^^^^^^^^^^^ not found in this scope
  17. Some errors have detailed explanations: E0412, E0425, E0432.
  18. For more information about an error, try `rustc --explain E0412`.
  19. error: could not compile `test_log` (bin "test_log") due to 3 previous errors

这就是我们对于Rust 的一种比丁真还要纯真的认识导致的,这时候我们把这个报错error[E0432]: unresolved import 'log'喂给GPT,人猿相揖别。只几个石头磨过,小儿时节。善于使用工具正是一个懒狗所需要的,

遇到错误 error[E0432]: unresolved import 'log' 表示Rust编译器无法找到你尝试引入的log库。这通常是因为以下几个原因:

  1. 未添加log库为依赖:确保你的Cargo.toml文件中已经添加了log库作为依赖。如果没有,你需要在 [dependencies] 部分添加它。对于最常见的使用场景,添加如下内容:
    1. [dependencies]
    2. log = "0.4" # 或者其它适用的版本号

然后在项目目录下运行 cargo update 来下载依赖。

2. Cargo特性(gated features):如果你的项目或某个依赖启用了特定的Cargo特性,并且这些特性影响了log的使用,确保正确配置了这些特性。检查Cargo.toml中的[features]部分和相关依赖的特性要求。

3. 路径问题:如果你的项目结构比较特殊,可能需要使用相对路径或绝对路径来正确引入log。但这通常不是导致上述错误的原因,因为log通常作为crate直接引入。

4. 编译目标或环境问题:确保你的编译目标和环境配置没有排除log库的编译或链接。这在交叉编译时可能会成为问题。

5. Cargo.lock的干扰:有时候,旧的Cargo.lock文件可能锁定了不兼容的依赖版本,导致新添加的依赖无法正确解析。尝试删除Cargo.lock文件(如果有),然后重新运行cargo buildcargo run让Cargo重新生成它。

解决方法通常是先检查并修正Cargo.toml,确保log库已经被正确添加为依赖,然后更新依赖并重新编译项目。如果问题依旧存在,检查是否有其他依赖或项目配置干扰了log的正确解析。

What can I say?答案是Cargo没学会,这时候我们修改Cargo.toml,访问log包的文档,可以看到当前的最新版本为0.4.21,在文件中添加这一段,

  1. [dependencies]
  2. log = "0.4.21"

接下来我们解决error[E0412]: cannot find type 'Yak' in this scope的问题,这个问题说明Yak并不是std里原本有的一个东西,当然也倒逼我们一定要看清楚源代码,这次我们直接读和理解这个报错,说的是在当前scope即作用域中找不到Yak,考虑到这个幺蛾子文档的习惯,我们直接在刚才文档的右上角搜索Yak,

![[Pasted image 20240628015106.png]]

这里我们看到shave it意为给它剃毛,考虑原本的代码中的find_a_razor函数即寻找剃刀也报错了error[E0425]: cannot find function find_a_razor in this scope,那么就很好理解了,Yak可能是被制造出来的一个例子库,我们尝试在Cargo.toml中依赖它,

  1. [dependencies]
  2. yak = "0.1.0"

但是很悲剧的是,这个函数并不存在,也就是这段代码纯是一段伪代码,那么我们直接看这段伪代码:

  1. use log::{info, warn};
  2. pub fn shave_the_yak(yak: &mut Yak) {
  3. info!(target: "yak_events", "Commencing yak shaving for {:?}", yak);
  4. loop {
  5. match find_a_razor() {
  6. Ok(razor) => {
  7. info!("Razor located: {}", razor);
  8. yak.shave(razor);
  9. break;
  10. }
  11. Err(err) => {
  12. warn!("Unable to locate a razor: {}, retrying", err);
  13. }
  14. }
  15. }
  16. }

假设Yak是一个struct,可以它有一个对应的impl,是shave,而还有一个函数find_a_razor是可以返回一个razor类型或者一个err类型的函数.那么我们可以手动补全这段代码:

  1. use std::error::Error;
  2. use std::fmt;
  3. use std::sync::Mutex;
  4. #[derive(Debug)]
  5. pub struct Yak
  6. {
  7.     yak_name: String,
  8.     is_shaved: bool
  9. }
  10. pub struct razor
  11. {
  12.     used_time: u32
  13. }
  14. #[derive(Debug)]
  15. pub struct err
  16. {
  17.     context: String
  18. }
  19. impl Error for err
  20. {
  21. }
  22. impl fmt::Display for err
  23. {
  24.     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
  25.     {
  26.         write!(f, "Error: {}", self.context)
  27.     }
  28. }
  29. impl Yak {
  30.     pub fn new(yak_name: String) -> Self {
  31.         Yak {
  32.             yak_name,
  33.             is_shaved: false,
  34.         }
  35.     }
  36.     pub fn get_yak_name(&self) -> &str {
  37.         &self.yak_name
  38.     }
  39.     pub fn set_yak_name(&mut self, new_name: String) {
  40.         self.yak_name = new_name;
  41.     }
  42.     pub fn is_shaved(&self) -> bool {
  43.         self.is_shaved
  44.     }
  45.     pub fn shave(&mut self, mut razor: razor)
  46.     {
  47.         self.is_shaved = true;
  48.         razor.used_time+=1;
  49.     }
  50. }
  51. impl fmt::Display for razor
  52. {
  53.     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
  54.     {
  55.         write!(f, "Razor used time: {}", self.used_time)
  56.     }
  57. }
  58. pub fn find_a_razor() -> Result<razor,err>
  59. {
  60.     let mut one_razor = razor{used_time:0};
  61.     if one_razor.used_time<100
  62.     {
  63.         one_razor.used_time+=1;
  64.         Ok(one_razor)
  65.     }
  66.     else
  67.     {
  68.         let the_err:err = err{context:"No razor found".to_string()};
  69.         Err(the_err)
  70.     }
  71. }

那么这段代码里就含有几个概念没有搞定,补全过程中极尽折磨:

  1. 枚举类型的泛型
  2. 分支结构
  3. Debug输出

枚举类型

这段代码中,Result<razor,err>是用到了枚举和泛型.

首先Rust的枚举更像是C的枚举的增强版本,C的枚举的几个成员是一个整数,可以按照默认的0-N来用,一般和switch结合增强状态机的可读性.但是很明显这样的成员很难满足Rust的灵活性的需求,尤其是这个场景,又要返回Ok(razor)类型,又要返回Err(err)类型.

那么可以理解Rust的枚举,它不只是为了用一系列代号代表这个类型的所有的可能,而且这个类型可能对应很多种基础类型,也可以被代表.

这样这一段可以理解了,Result<T,E>是一个枚举类型,源代码我们可以在这里找到:

  1. pub enum Result<T, E> {
  2. Ok(T),
  3. Err(E),
  4. }

可能还是比较难理解,因为这里掺杂了泛型:

  1. pub enum OBJ
  2. {
  3. A(u32),
  4. B(u64)
  5. }

上边这段代码代表OBJ只可能是A或者B,两种情况,但是A实际上包裹---可以理解为Au32类型的一个代号,但是不是直接的u32而是A携带了这样一个变量,B也同理.

考虑到使用了泛型,这就意味着我们可以自定义OkErr各自包裹着什么.

分支结构

这里主要卡住人的是一点,rustif后边的条件是没有括号的.

Debug输出

如果使用了{:?}这种输出,则需要为这个需要输出的类实现一个Debug特性,或者使用#[derive(Debug)].

Cargo的输出等级

编辑main.rs之后发现不能输出:

  1. mod yak;
  2. use log::{info, warn};
  3. use yak::{Yak,find_a_razor};
  4. pub fn shave_the_yak(yak: &mut Yak)
  5. {
  6.     info!(target: "yak_events", "Commencing yak shaving for {:?}", yak);
  7.     loop
  8.     {
  9.         match find_a_razor()
  10.         {
  11.             Ok(razor) =>
  12.             {
  13.                 info!("Razor located: {}", razor);
  14.                 yak.shave(razor);
  15.                 break;
  16.             }
  17.             Err(err) =>
  18.             {
  19.                 warn!("Unable to locate a razor: {}, retrying", err);
  20.             }
  21.         }
  22.     }
  23. }
  24. fn main()
  25. {
  26.     env_logger::init();
  27.     let mut yak = Yak::new("Fred".to_string());
  28.     shave_the_yak(&mut yak);
  29.     println!("Hello, world!");
  30. }

这里是存在两个问题:

  1. 错误信息没有输出到工作台
  2. Cargo的输出没有到info这个级别
输出到工作台

编辑Cargo.toml增加一个依赖:

  1. [package]
  2. name = "test_log"
  3. version = "0.1.0"
  4. edition = "2021"
  5. [dependencies]
  6. log = "0.4.21"
  7. env_logger = "0.8"

编辑main.rs,使用env_logger::init();即可.

修改cargodebug等级

使用这个方法即可:

  1. RUST_LOG=info cargo run

os工程适配log

我们首先看题目中给的参考代码:

  1. use core::fmt;
  2. use lazy_static::lazy_static;
  3. use log::{self, Level, LevelFilter, Log, Metadata, Record};
  4. use crate::sync::SpinNoIrqLock as Mutex;
  5. lazy_static! {
  6. static ref LOG_LOCK: Mutex<()> = Mutex::new(());
  7. }
  8. pub fn init() {
  9. static LOGGER: SimpleLogger = SimpleLogger;
  10. log::set_logger(&LOGGER).unwrap();
  11. log::set_max_level(match option_env!("LOG") {
  12. Some("error") => LevelFilter::Error,
  13. Some("warn") => LevelFilter::Warn,
  14. Some("info") => LevelFilter::Info,
  15. Some("debug") => LevelFilter::Debug,
  16. Some("trace") => LevelFilter::Trace,
  17. _ => LevelFilter::Off,
  18. });
  19. }
  20. #[macro_export]
  21. macro_rules! print {
  22. ($($arg:tt)*) => ({
  23. $crate::logging::print(format_args!($($arg)*));
  24. });
  25. }
  26. #[macro_export]
  27. macro_rules! println {
  28. ($fmt:expr) => (print!(concat!($fmt, "\n")));
  29. ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
  30. }
  31. /// Add escape sequence to print with color in Linux console
  32. macro_rules! with_color {
  33. ($args: ident, $color_code: ident) => {{
  34. format_args!("\u{1B}[{}m{}\u{1B}[0m", $color_code as u8, $args)
  35. }};
  36. }
  37. fn print_in_color(args: fmt::Arguments, color_code: u8) {
  38. use crate::arch::io;
  39. let _guard = LOG_LOCK.lock();
  40. io::putfmt(with_color!(args, color_code));
  41. }
  42. pub fn print(args: fmt::Arguments) {
  43. use crate::arch::io;
  44. let _guard = LOG_LOCK.lock();
  45. io::putfmt(args);
  46. }
  47. struct SimpleLogger;
  48. impl Log for SimpleLogger {
  49. fn enabled(&self, _metadata: &Metadata) -> bool {
  50. true
  51. }
  52. fn log(&self, record: &Record) {
  53. if !self.enabled(record.metadata()) {
  54. return;
  55. }
  56. /*
  57. if let Some(tid) = processor().tid_option() {
  58. print_in_color(
  59. format_args!(
  60. "[{:>5}][{},{}] {}\n",
  61. record.level(),
  62. crate::arch::cpu::id(),
  63. tid,
  64. record.args()
  65. ),
  66. level_to_color_code(record.level()),
  67. );
  68. } else {
  69. */
  70. print_in_color(
  71. format_args!(
  72. "[{:>5}][{},-] {}\n",
  73. record.level(),
  74. crate::arch::cpu::id(),
  75. record.args()
  76. ),
  77. level_to_color_code(record.level()),
  78. );
  79. //}
  80. }
  81. fn flush(&self) {}
  82. }
  83. fn level_to_color_code(level: Level) -> u8 {
  84. match level {
  85. Level::Error => 31, // Red
  86. Level::Warn => 93, // BrightYellow
  87. Level::Info => 34, // Blue
  88. Level::Debug => 32, // Green
  89. Level::Trace => 90, // BrightBlack
  90. }
  91. }

我们可以看到参考代码自己实现了一个SimpleLogger类型,并且给它实现了Log这个特性,这是起初很让人难以理解的,但是这让我们想到一个细节,即我们实际上使用了env_logger这个库,用一句看似简单的初始化完成了我们的任务,即把info等宏和硬件输出联系在一起,所以因此我们也需要自己去实现一个带有Log特性的SimpleLogger类,由于我们有了参考源码,实际上的工作反而没有那么困难.

[[012 彩色化LOG#^bf99b4|这里]]实际上又进行了一个简单的Log特质的实现,因为思路先后问题,写到了下一节.

简单的Log特质的实现

^bf99b4

可以在这里看到Log特质实现的时候需要实现的方法为enabled,log,flush.并且可以在这里看到一个小的样例,

  1. use log::{Record, Level, Metadata};
  2. struct SimpleLogger;
  3. impl log::Log for SimpleLogger {
  4. fn enabled(&self, metadata: &Metadata) -> bool {
  5. metadata.level() <= Level::Info
  6. }
  7. fn log(&self, record: &Record) {
  8. if self.enabled(record.metadata()) {
  9. println!("{} - {}", record.level(), record.args());
  10. }
  11. }
  12. fn flush(&self) {}
  13. }

可以根据在在这里看到Log特质实现的时候需要实现的方法,

  1. enabled方法是传入一个Metadata的引用返回一个bool的函数,用于判断当前的这个数据是不是应该被logger给记录下来,样例里简单地写成了只需要<=Level::Info即可.
  2. log方法是传入一个Record,因为Rcord里存在很多信息,然后对它进行判定,然后按照我们需要的方式来进行日志记录.这里就是直接判断等级是不是够了,然后输出其levelargs
  3. flush方法:
    1. 在Rust的日志记录系统中,特别是使用log库和相关的宏如info!, warn!, error!等进行日志记录时,这些宏会调用日志框架来记录消息。通常情况下,当你的应用程序正常退出时,日志框架会自动处理缓冲区中的日志记录,确保所有未提交的日志条目都被写入到日志目的地,比如控制台或文件。
    2. 然而,有时候应用程序可能在异常情况下终止,或者日志框架的默认行为可能不足以满足你的需求。在这种情况下,日志框架通常会提供一个方法,允许你显式地触发日志的刷新,以确保所有日志记录都被正确处理。这个方法通常称为flush
    3. 在这个例子里,因为我们的日志是直接输出到命令行的,因此只需要实现为空即可.

为一个Logger类实现Log特质之后,我们可以直接使用info!等宏来实现输出.

参照参考代码写出来的Logger如下:

  1. use core::fmt;
  2. use log::{self,Level,LevelFilter,Metadata,Log,Record};
  3. struct SimpleLogger;
  4. impl Log for SimpleLogger
  5. {
  6.     fn enabled(&self, metadata: &Metadata) -> bool
  7.     {
  8.         true
  9.     }
  10.     fn log(&self, record: &Record)
  11.     {
  12.         if !self.enabled(record.metadata())
  13.         {
  14.             return;
  15.         }
  16.         print_in_color(
  17.             format_args!(
  18.                 "[{:>5}] {}\n",
  19.                 record.level(),
  20.                 record.args()
  21.             ),
  22.             level_to_color_code(record.level()),
  23.         );
  24.     }
  25.     fn flush(&self) {}
  26. }
  27. fn print_in_color(args: fmt::Arguments, color_code: u8)
  28. {
  29.     println!("\u{1B}[{}m{}\u{1B}[0m", color_code, args);
  30. }
  31. fn level_to_color_code(level: Level) -> u8 {
  32.     match level {
  33.         Level::Error => 31, // Red
  34.         Level::Warn => 93,  // BrightYellow
  35.         Level::Info => 34,  // Blue
  36.         Level::Debug => 32, // Green
  37.         Level::Trace => 90, // BrightBlack
  38.     }
  39. }
  40. pub fn init()
  41. {
  42.     static LOGGER: SimpleLogger = SimpleLogger;
  43.     log::set_logger(&LOGGER).unwrap();
  44.     // log::set_max_level(LevelFilter::Trace);
  45.     log::set_max_level(match option_env!("LOG") {
  46.         Some("error") => LevelFilter::Error,
  47.         Some("warn") => LevelFilter::Warn,
  48.         Some("info") => LevelFilter::Info,
  49.         Some("debug") => LevelFilter::Debug,
  50.         Some("trace") => LevelFilter::Trace,
  51.         _ => LevelFilter::Off,
  52.     });
  53. }

写出来的main.rs如下:

  1. // os/src/main.rs
  2. #![no_std]
  3. #![no_main]
  4. #![feature(panic_info_message)]
  5. use core::{arch::global_asm};
  6. use delay::sleep;
  7. use log::{debug, info, error};
  8. #[macro_use]
  9. mod console;
  10. mod sbi;
  11. mod lang_items;
  12. mod delay;
  13. mod logging;
  14. //use sbi::shutdown;
  15. global_asm!(include_str!("entry.asm"));
  16. #[no_mangle]
  17. pub fn rust_main() -> ! {
  18.     extern "C" {
  19.         fn stext(); // begin addr of text segment
  20.         fn etext(); // end addr of text segment
  21.         fn srodata(); // start addr of Read-Only data segment
  22.         fn erodata(); // end addr of Read-Only data ssegment
  23.         fn sdata(); // start addr of data segment
  24.         fn edata(); // end addr of data segment
  25.     }
  26.     clear_bss();
  27.     logging::init();
  28.     println!("Hello World");
  29.     info!(".text [{:#x}, {:#x})", stext as usize, etext as usize);
  30.     debug!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize);
  31.     error!(".data [{:#x}, {:#x})", sdata as usize, edata as usize);
  32.     panic!("Shutdown machine!");
  33. }
  34. fn clear_bss() {
  35.     extern "C" {
  36.         fn sbss();
  37.         fn ebss();
  38.     }
  39.     (sbss as usize..ebss as usize).for_each(|a| {
  40.         unsafe { (a as *mut u8).write_volatile(0) }
  41.     });
  42. }

这里只讲关键点:

  1. \u{1B}[{}m{}\u{1B}[0m里的{}为占位符,第一个{}对应的是输出的颜色,第二个是输出的内容
  2. format_args!这个宏是一个非常神奇的宏,可以实现传入一个字符串,然后把占位符用后边传入的参数实现,就像C里边printf的格式化和python里边f"string{var}".
  3. 在运行cargo时,增加env LOG="info",可以有效传入环境变量参数,注意不要搞错大小写什么的以至于贻笑大方,这里注意不是在运行qemu的时候这么做.

[rCore学习笔记 012]彩色化LOG的更多相关文章

  1. java学习笔记12--国际化

    java学习笔记12--国际化 国际化的操作就是指一个程序可以同时适应多门语言,即:如果现在程序者是中国人,则会以中文为显示文字,如果现在程序的使用者是英国人,则会以英语为显示的文字,也就是说可以通过 ...

  2. CNN学习笔记:池化层

    CNN学习笔记:池化层 池化 池化(Pooling)是卷积神经网络中另一个重要的概念,它实际上是一种形式的降采样.有多种不同形式的非线性池化函数,而其中“最大池化(Max pooling)”是最为常见 ...

  3. Python学习笔记012——装饰器

    1 装饰器 1.1装饰器定义 在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator). 1.2 装饰器分类 装饰器:函数装饰器,类装饰器,函数的装饰器,类的装饰器 装饰器:函数装饰函 ...

  4. React学习笔记-5-初始化阶段介绍

    初始化阶段可以使用的函数:getDefaultProps:只调用一次,实例之间共享引用.只有在组件的第一个实例被初始化的时候,才会调用他,然后react会把这个函数的返回结果保存起来,从第二个实例开始 ...

  5. Yii2学习笔记:汉化yii,设置表单的描述(属性标签attributeLabels)

    一:汉化框架 框架汉化在这里设置,如果不生效,前台后台的配置文件都设置下应该就可以了 二:汉化表单 汉化表单,直接在模型层设置,例如: 原来的联系我们表单 汉化后: ] 这种汉化在哪里修改呢?其实是设 ...

  6. python自动化学习笔记11-自动化测试UTP框架

    前面基本的unittest及ddt已经学过了,现在我们系统把这些知识结合起来,写一个简单的UTP自动化测试框架: 我们先来建基础目录,首先新建一个项目,项目下建父目录UTP,conf目录,用来存放配置 ...

  7. SAS学习笔记63 如何导出Log

    如上,将Log输出,然后又恢复到SAS系统里面的Log,把需要运行的程序放到他们中间就可以了.这种方法不会出现Log打印满了的情况 这种是先输出在SAS系统里面,然后在输出,在SAS里面Log的行是有 ...

  8. Vue.js官方文档学习笔记(二)组件化应用的构建

    组件化应用的构建 组件化应用允许我们使用小型.独立和通常可复用的组件构建大型应用. Vue注册组件 Vue.component('todo-item',{template:'<li>这是个 ...

  9. Selenium学习笔记之外部化相关测试数据---xml

    我们也可以用xml来定义一个信息更为丰富的UIMap.xml文件,比如,额外还添加控件所属的页,控件的类型,然后解析构建一个XMLParser类来读取相应的值. <?xml version=&q ...

  10. ASP.NET本质论第一章网站应用程序学习笔记3-对象化的Http

    在.NET环境下,万物皆对象,在HttpRuntime收到请求之后,立即将通过HttpWorkerRequest传递的参数进行分析和分解,创建方便用于网站应用程序处理用的对象,其中主要涉及到两个对象类 ...

随机推荐

  1. tcc-transaction源码详解

    更多优秀博文,请关注博主的个人博客:听到微笑的博客 本文主要介绍TCC的原理,以及从代码的角度上分析如何实现的:不涉及具体使用示例.本文通过分析tcc-transaction源码带大家了解TCC分布式 ...

  2. 8.17考试总结(NOIP模拟42)[卷·简单题·粉丝·字符串]

    你的败因只有一个,就是与我为敌. ­ T1 卷 解题思路 乍一看,简单的树形 DP . 后来一看数据范围,发现事实并非如此.(\((10^9)^{2\times 10^5}\)????) 毕竟取 \( ...

  3. 【深度学习】c++部署onnx模型(Yolov5、PP-HumanSeg、GoogLeNet、UNet)

    这两天部署了好多模型,记录一下.代码链接. onnxruntime在第一张图的推理上比opencv快很多,但在后面的图上略微慢了一点. 不同的模型的部署时的输出不同,处理时需要对输出比较了解,下面分别 ...

  4. Web 页面性能衡量指标-以用户为中心的效果指标

    Web 页面性能衡量指标-以用户为中心的性能指标 以用户为中心的性能指标是理解和改进站点体验的关键点 一.以用户为中心的性能指标 1. 指标是用来干啥的? 指标是用来衡量性能和用户体验的 2. 指标类 ...

  5. RHCSA认证学习_尝试

    第一天 一,linux系统的基本概念以及命令终端字段含义介绍 linux系统的基本概念: ·多用户的系统:允许同时执行多个任务 ·多任务的系统:允许同时执行多个任务 ·严格区分大小写:命令,选项,参数 ...

  6. IDEA顺序启动多个Spring Boot微服务

    上个月公司新开发的一个项目,需要使用微服务,将单体服务拆分成多个微服务.但是每次修改代码之后都需要启动多个微服务,改个代码,都要修改五分钟,启动半小时,但是idea可以设置将多个服务依次启动,减少操作 ...

  7. 面试必会 --> MyBatis篇

    什么是MyBatis Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动.创建连接.创建statement等繁杂的过程 ...

  8. INFINI Labs 产品更新 | Console 告警中心 UI 全新改版,新增 Dashboard 全屏模式等功能

    本次 INFINI Labs 产品更新主要发布 Console v1.7.0,重点优化了 Console 告警中心和数据看板 Dashboard 可视化功能.详细介绍如下: 优化告警中心 UI 上个版 ...

  9. BC6-牛牛的第二个整数

    题目描述 牛牛从键盘上输入三个整数,并尝试在屏幕上显示第二个整数. 输入描述 一行输入 3 个整数,用空格隔开. 输出描述 请输出第二个整数的值. 示例 1 输入:1 2 3 输出:2 解题思路 方案 ...

  10. RequestBodyAdvice和注解方式进行统一参数处理demo

    RequestBodyAdvice和注解方式进行统一参数处理demo @Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(Rete ...