rust 如何减少端子重绘时的 Flink ?

wmvff8tz  于 4个月前  发布在  Flink
关注(0)|答案(2)|浏览(71)

我有一个程序,可以显示并行运行的一些命令的状态

fmt    ✔
clippy cargo clippy --tests --color always ... 
tests  cargo test --color always ..

字符串
该程序是我的第一个依赖于多线程的程序,我有一些线程运行那些程序,只要它们“可用”,我有一个线程(主要的一个)致力于等待新的结果(这是非常罕见的,因为作业往往运行至少几秒钟,而且作业相对较少,最多并行10次),并在循环中删除和重新打印事物的状态。
在软件的这一部分,我不打印命令的输出,只打印正在运行的命令和一些asynchronspinner。
我不知道这些事情应该怎么做,所以我设法限制重画至少40毫秒:

const AWAIT_TIME: Duration = std::time::Duration::from_millis(40);
fn delay(&mut self) -> usize {
    let time_for = AWAIT_TIME
        - SystemTime::now()
            .duration_since(self.last_occurence)
            .unwrap();
    let millis: usize = std::cmp::max(time_for.as_millis() as usize, 0);
    if millis != 0 {
        sleep(time_for);
    }
    self.last_occurence = SystemTime::now();
    millis
}
while let Some(progress) = read(&rx) { ... }    
job_display.refresh(&tracker, delay);
delay = job_starter.delay();

所以我最终跟踪了写入的行数和字符数,并将它们全部删除:

struct TermWrapper {
    term: Box<StdoutTerminal>,
    written_lines: u16,
    written_chars: usize,
}

...

pub fn clear(&mut self) {
    (0..self.written_lines as usize).for_each(|_| {
        self.term.cursor_up().unwrap();
        self.term.carriage_return().unwrap();
        self.term.delete_line().unwrap();
    });
    self.written_lines = 0;
    self.written_chars = 0;
}


它工作,但往往 Flink ,特别是在嵌入式终端。
我的下一个想法是存储打印字符串的散列,如果可以的话跳过重绘。
是否有一些已知的模式,我可以应用到一些更好的输出?
我可以使用哪些常用策略?

bkkx9g8r

bkkx9g8r1#

更新终端时保证不 Flink 的最低要求是:不要发送一个东西,然后用其他东西覆盖它(在一个单一的“框架”的绘图)。在清除的情况下,我们可以重申该规则更具体:**不要清除要放入文本的区域。*相反,只清除那些你知道你没有在里面放文字的区域(如果那里有以前的文字)。
传统的终端命令集包含一个非常有用的工具:“clear to end of line”命令。您可以使用它的方式是:
1.将光标移动到要替换文本的行的开头。
1.写出文本,
结尾不带任何换行符或CRLF *
1.写“clear to end of line”。(在crossterm中,这是ClearType::UntilNewLine。)
在发送clear命令后,该行的其余部分将被清除(就像你碰巧写了确切的空格数来完全填满该行一样)。这样,你需要跟踪你正在写的行,但你不需要跟踪你写的每个字符串的确切 * 宽度 *。
除此之外,对于任意2D屏幕布局有用的下一步是记住之前发送到终端的文本,并且只发送需要更改的文本-在Rust中,tui crate提供了这一点,并且您还可以找到用于相同目的的着名C库curses的绑定。

neekobn8

neekobn82#

另一件需要考虑的事情是尽量减少写出的次数,并尝试在一次write()中写入(syscall)整个更新序列,包括光标定位和绘制。
一个真实的例子是lldb。当你在其中删除一个字符时,它不仅会做不必要的光标位置和重绘,而且最重要的是会刷新转义序列的每个字节的输出。
而在GNU Bash中,当你在下一行的开头删除char时,它会做很多^[C s来移动光标,但是它只写一次,所以你不会注意到任何 Flink ,即使是通过一个糟糕的高延迟ssh连接。

相关问题