笔者大多数的开发在 Linux 下,多处用到进度条的场景,但又无需用到图形化界面,因此就想着弄个 console 下的进度条显示。php
清行显示java
//清行处理操做 int currentLineCursor = Console.CursorTop;//记录当前光标位置 Console.SetCursorPosition(0, Console.CursorTop);//将光标至于当前行的开始位置 Console.Write(new string(' ', Console.WindowWidth));//用空格将当前行填满,至关于清除当前行 Console.SetCursorPosition(0, currentLineCursor);//将光标恢复至开始时的位置
若是要清除上一行,只需在清行处理操做前将调整光标位置提早一行,即:Console.SetCursorPosition(0, Console.CursorTop - 1);
。紧接着Console.WriteLine(/*something*/);
,便可实如今控制台末尾行重复输出。python
多线程下的输出显示ubuntu
多线程下最容易出现的问题就是一个线程的输出覆盖其余线程的输出,或者是一个线程紧跟着上一个线程输出而没有换行,这些状况多会致使输出的混乱。为了,解决这样的问题,特地实现一个专门的输出类来进行输出显示:c#
public class Consoler { private static string lastContext = "";//用于记录上次写的内容 private static readonly object _lock = new object();//加锁保证只有一个输出 public static void Write(string context) { lastContext = context;//记录上次写的内容 lock (_lock) { Console.Write(context); } } /// <summary> /// 覆写 /// </summary> /// <param name="context"></param> public static void OverWrite(string context = null) { lastContext = context;//记录上次写的内容 var strLen = context?.Length ?? 0; //空白格的长度,考虑到内容可能超出一行的宽度,因此求余。 var blankLen = Console.WindowWidth - strLen % Console.WindowWidth - 1; var rowCount = strLen / Console.WindowWidth; Console.SetCursorPosition(0, Console.CursorTop - rowCount); //空白只需填充最后一行的剩余位置便可。 lock (_lock) { Console.Write(context + new string(' ', blankLen)); } } public static void WriteLine(string context = null) { ClearConsoleLine();//清除最后一行 lock (_lock) { Console.WriteLine(context); if (!string.IsNullOrWhiteSpace(lastContext)) Console.Write(lastContext);//从新输出最后一次的内容,不然有较明显的闪烁 lastContext = null; } } public static void ClearConsoleLine(int invertedIndex = 0) { int currentLineCursor = Console.CursorTop; int top = Console.CursorTop - invertedIndex; top = top < 0 ? 0 : top; Console.SetCursorPosition(0, top); Console.Write(new string(' ', Console.WindowWidth - 1)); Console.SetCursorPosition(0, currentLineCursor); } }
实际测试时,使用多 Task (模拟多线程)去进行输出实验:多线程
static void Main(string[] args) { Console.WriteLine("Hello World!"); var task1 = Task.Run(() => { int count = 0, w, lw, rw; float p = 0; while (true) { w = (int)(Console.WindowWidth * 0.6); count %= 75; p = count++ / 74f; lw = (int)(p * w); rw = w - lw; Consoler.OverWrite($"from task1, [{new string('#', lw) + new string(' ', rw)}]:{p:#.00%}"); Thread.Sleep(100); } }); var task2 = Task.Run(() => { while (true) { Consoler.WriteLine($"from task2, now:{DateTime.Now}"); Thread.Sleep(5000); } }); var task3 = Task.Run(() => { var rd = new Random(); while (true) { Consoler.WriteLine($"from task3, {new string('+', (int)(rd.NextDouble() * Console.WindowWidth))}"); Thread.Sleep(rd.Next(5000)); } }); Task.WaitAll(task1); }
最终输出结果:dom
from task2, now:6/5/19 8:10:24 PM from task3, +++++++++++++++++++++++++++++++++ from task2, now:6/5/19 8:10:29 PM from task3, +++++++++++++++++++++++++ from task3, ++++ from task2, now:6/5/19 8:10:34 PM from task3, +++++++++++++++++++++++ from task3, ++++++++++++ from task3, ++++++ from task2, now:6/5/19 8:10:44 PM from task1, [########################### ]:58.11%
task1 用来进行进度条的输出,task2 和 task3 进行随机输出。能够看出,task1 永远在最后一行进行进度更新,其余输出任然能够正常进行。实现的效果和 ubuntu 下执行更新命令sudo apt-get update
的输出相似。异步
总结性能
虽然该例子是在 c#下完成的,但在 python,c,java 中通用。为了保证输出的有序性,程序中加了锁,影像了多线程的效率,可是对于界面显示是足够的。若是须要高性能,那么考虑使用相似于队列式的异步更新输出显示的方法。测试