콘솔 애플리케이션에 활동 표시기 표시

개요



콘솔 응용 프로그램에서 무거운 처리를 실행 중임을 사용자에게 알리기 위해 활동 표시기를 표시하는 프로그램을 C#과 F#으로 작성했습니다.



일정 시간마다 ...를 표시하기 위해 Rx ( Observable.Timer )를 사용했습니다.
  • 処理中
  • 処理中.
  • 処理中..
  • 処理中...
  • 처리가 끝날 때까지 위의 표시를 반복하고 처리가 완료되면 아래의 표시로 덮어 씁니다.
  • 処理完了

  • C# 버전



    nuget으로 System.Reactive를 설치하십시오.
    using System;
    using System.Reactive.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    
    class Program {
    
      // アクティビティインジケータを出力する関数
      static void IndicationPrinter(string msg1, string msg2, int i) {
        Console.SetCursorPosition(0, Console.CursorTop);
        if (i < 0) {
          Console.WriteLine(msg2);
        } else {
          var n = i % 4;
          Console.Write($"{msg1}{new string('.', n)}{new string(' ', 3 - n)}");
        }
      }
    
      // インジケータを出力しながら関数funcをする非同期で実行する関数
      static Task<T> RunWithActivityIndicator<S, T>(string msg1, string msg2, Func<S, T> func, S arg) {
    
        var sTimer = Observable.Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(0.2));
        var timerSubscription = sTimer.Subscribe(i =>
          IndicationPrinter(msg1, msg2, (int)i));
    
        return Task.Run(() => {
          return func(arg);
        }).ContinueWith((Task<T> t) => {
          timerSubscription.Dispose();
          IndicationPrinter(msg1, msg2, -1);
          return t.Result;
        });
      }
    
      static void Main(string[] args) {
    
        Console.WriteLine("C# Ver.");
        //Console.CursorVisible = false; //カーソルを消したい場合
    
        Func<string, string> heavyWeightFunc1 = (string arg) => {
          Thread.Sleep(2500);
          return $"=={arg}==";
        };
    
        // 非常に時間がかかる関数1 (Func<int>) 
        Func<int> heavyWeightFunc2 = () => {
          Thread.Sleep(1500);
          return 0;
        };
    
        var msg1 = "処理中";
        var msg2 = "処理完了";
    
        var task1 = RunWithActivityIndicator(msg1, msg2, heavyWeightFunc1, "hoge");
        Console.WriteLine($"処理結果:{task1.Result}");
    
        Console.ReadKey();
      }
    }
    

    F#판



    nuget으로 FSharp.Control.Reactive를 설치하십시오.
    open System
    open System.Reactive.Linq
    open FSharp.Control.Reactive
    open System.Threading
    open System.Threading.Tasks
    
    // アクティビティインジケータを出力する関数
    let indicationPrinter msg1 msg2 i = 
      Console.SetCursorPosition(0, Console.CursorTop) |> ignore
      if i < 0 then
        printfn "%s" msg2
      else
        match i%4 with
        | 0 -> ignore( printf "%s" (msg1+"   "))
        | 1 -> ignore( printf "%s" (msg1+".  "))
        | 2 -> ignore( printf "%s" (msg1+".. "))
        | _ -> ignore( printf "%s" (msg1+"..."))
    
    // インジケータを出力しながら関数funcをする非同期で実行する関数
    let runWithActivityIndicator (msg1,msg2) (func:'S->'T) arg =
    
      let indicationPrinter = indicationPrinter msg1 msg2
    
      let sTimer = Observable.Timer(TimeSpan.FromSeconds(0.),TimeSpan.FromSeconds(0.2))
      let timerSubscription = sTimer.Subscribe( fun i -> int(i) |> indicationPrinter  )
    
      let task = async { return func arg } |> Async.StartAsTask
      task.ContinueWith( fun (t:Task<'T>) -> 
        timerSubscription.Dispose()
        indicationPrinter -1
        t.Result ) 
    
    [<EntryPoint>]
    let main argv =
    
      printfn "F# Ver."
      //Console.CursorVisible <- false; // カーソルを消したい場合
    
      // 非常に時間がかかる関数1 (string->string) 
      let heavyWeightFunc1 arg =
        Thread.Sleep(1500)
        "==" + arg + "=="
    
      // 非常に時間がかかる関数2 (unit->string) 
      let heavyWeightFunc2 () =
        Thread.Sleep(2500)
        0
    
      // 非常に時間がかかる関数3 (unit->unit) 
      let heavyWeightFunc3 () =
        Thread.Sleep(1000)
    
      let msg = ("処理中","処理完了")  
      let task1 = runWithActivityIndicator msg heavyWeightFunc1 "hoge"
      printfn "%s" ("処理結果 : " + task1.Result )
    
      let task2 = runWithActivityIndicator msg heavyWeightFunc2 ()
      printfn "%s" ("処理結果 : " + (task2.Result.ToString()) )
    
      let task3 = runWithActivityIndicator msg heavyWeightFunc3 ()
      task3.Wait()
      printfn "." 
    
      Console.ReadKey() |> ignore
      0
    

    참고 자료


  • Reactive Extensions 재입문 4 「타이머 계열의 팩토리 메소드
  • F# Async Guide
  • C# 비동기 처리 콘솔에서 빙글빙글 로딩 애니메이션 보기
  • 처리 중에 빙글빙글 돌리는 아이콘의 이름은 무엇이 맞습니까? 진척 인디케이터 or…?
  • 좋은 웹페이지 즐겨찾기