Индикатор выполнения консольного приложения работает медленно - PullRequest
0 голосов
/ 24 июня 2018

У меня есть метод, который загружает файл по TCP-соединению, и я хочу отобразить на консоли индикатор завершения загрузки. В настоящее время я использую метод, который вызывает события для отображения индикатора выполнения и его обновления.

Моя проблема в том, что дисплей не асинхронный, и он сильно замедляет процесс загрузки. Я пытался обрабатывать события с помощью Задач, но не смог получить хороший результат, так как несколько потоков одновременно обновляли бы индикатор выполнения, и это приводило к беспорядку.

Способ загрузки:

public void DownloadFile(Stream stream)
{
    if (!stream.CanWrite)
    {
        // The stream can't be written : invalid argument
        throw new ArgumentException();
    }

    // Get the data lenght first
    var dataLength = long.Parse(ReadLine());

    // Send ready flag
    WriteLine("{OK}");

    var buffer = new byte[DEFAULT_BUFFER_SIZE];
    long bytesWritten = 0;
    try
    {
        // Notify that the stream transfert started if the handler has been implemented
        StreamTransfertStartEvent?.Invoke(dataLength);

        int bytesRead;
        while ((bytesRead = binaryReader.Read(buffer, 0, buffer.Length)) > 0)
        {
            stream.Write(buffer, 0, bytesRead);
            bytesWritten += bytesRead;

            // Notify that the stream transfert progress changed if the handler has been implemented
            StreamTransfertProgressEvent?.Invoke(bytesWritten);

            // The file has been totally written
            if (bytesWritten == dataLength)
            {
                break;
            }
        }
    }
    catch (Exception)
    {
        StreamTransfertFailEvent?.Invoke();
        throw new NetworkException();
    }
}

Вы можете увидеть в коде выше 3 события, которые я использую для обновления индикатора выполнения:

  • StreamTransfertStartEvent
  • StreamTransfertProgressEvent
  • StreamTransfertFailEvent

А для кода обновления индикатора выполнения (только код, вызываемый обработчиком StreamTransfertProgressEvent):

public static void Update(long current)
{
    var newCompletion = (int)((decimal)current / total * 100);

    // Transfert progressed
    if (completion != newCompletion)
    {
        completion = newCompletion;

        if (completion % 2 == 0)
        {
            Console.SetCursorPosition(1, lastLine - 1);
            Console.Write(new string('=', completion / 2 - 1));
            Console.Write('>');
        }

        var leftStart = 52 - total.ToString().Length - 7 - current.ToString().Length;
        Console.SetCursorPosition(leftStart, lastLine);
        Console.Write(current);

        // Transfert finished
        if (completion == 100)
        {
            Console.SetCursorPosition(50, lastLine - 1);
            Console.Write('=');

            End();
        }
    }
}
...