Не удается получить данные в реальном времени через синхронизациюContext.Post() и progress.Report() в асинхронной задаче

Я пытаюсь собрать выходные данные в реальном времени из общедоступной асинхронной задачи RunProcessAsync() и отправить в Form1 через синхронизациюContext.Post() и progress.Report() для обработки там, для целей отладки метки времени добавляются как в выходные данные, так и в полученные данные. код RunProcessAsync() изменен с https://gist.github.com/NSouth/6d44d07db97df7d41bce33ac3117fdeb.
Полученные данные сохраняются в Form1 и выводятся с помощью btnShow()

Обнаружено, что progress.Report() отправляет данные одновременно с stdOutBuilder.Append(), но synchronizeContext.Post() отправляет после RunProcessAsync(). Оба данных поступают в Form1 после завершения RunProcessAsync().

Я пытаюсь добавить System.Windows.Forms.Application.DoEvents();, но никаких улучшений.

These are the data collected with timestamp

processStartInfo.FileName = @"C:\WINDOWS\system32\cmd.exe";  
processStartInfo.Arguments = @"/k Dir C:\  /on ";

stdOutBuilder.Append()
08:05.407  16/07/2020  22:58    <DIR>          AndroidStudio  
08:05.407  28/06/2020  21:03    <DIR>          App  
08:05.408  21/06/2017  20:50    <DIR>          MP_Upload  
  
VS2013 debug Output  
08:05.407  16/07/2020  22:58    <DIR>          AndroidStudio  
08:05.407  28/06/2020  21:03    <DIR>          App  
08:05.408  21/06/2017  20:50    <DIR>          MP_Upload  
  
m_SynchronizationContext.Post
08:05.452  08:05.452  16/07/2020  22:58    <DIR>          AndroidStudio  
08:05.453  08:05.453  28/06/2020  21:03    <DIR>          App  
08:05.453  08:05.453  21/06/2017  20:50    <DIR>          MP_Upload  
  
progress.Report
08:05.452  08:05.407  16/07/2020  22:58    <DIR>          AndroidStudio  
08:05.453  08:05.408  28/06/2020  21:03    <DIR>          App  
08:05.454  08:05.408  21/06/2017  20:50    <DIR>          MP_Upload  
^^^^^      ^^^^^------- timestamp same as stdOutBuilder.Append()  
^^^^^------ arrive after RunProcessAsync() completed  
  

Может ли кто-нибудь помочь мне, чтобы Form1 могла получать данные в режиме реального времени?

Ниже используется код:


public async Task<Result> RunProcessAsync(ProcessStartInfo startInfo, IProgress<ExecuteDosCmd.Form1.ProgressObject> progress, string stdIn = null, int? timeoutMs = null)
// modify from https://gist.github.com/NSouth/6d44d07db97df7d41bce33ac3117fdeb
{
......

    process.OutputDataReceived += (s, e) =>
    {
        if (e.Data == null)
        {
            stdOutCloseEvent.TrySetResult(true);
        }
        else
        {   
            stdOutBuilder.Append(DateTime.Now.ToString("mm:ss.fff  ") + e.Data +"\n");
            //08:05.407  16/07/2020  22:58    <DIR>          AndroidStudio
            //08:05.407  28/06/2020  21:03    <DIR>          App
            //08:05.408  21/06/2017  20:50    <DIR>          MP_Upload

            debugPr(e.Data);
            //08:05.407  16/07/2020  22:58    <DIR>          AndroidStudio
            //08:05.407  28/06/2020  21:03    <DIR>          App
            //08:05.408  21/06/2017  20:50    <DIR>          MP_Upload

            m_SynchronizationContext.Post(_ => ExecuteDosCmd.Form1.form1.updateProgress01(DateTime.Now.ToString("mm:ss.fff  ") + e.Data + "\n"), null);
            //08:05.452  08:05.452  16/07/2020  22:58    <DIR>          AndroidStudio
            //08:05.453  08:05.453  28/06/2020  21:03    <DIR>          App
            //08:05.453  08:05.453  21/06/2017  20:50    <DIR>          MP_Upload
            
            //System.Windows.Forms.Application.DoEvents(); 
            progress.Report(new ExecuteDosCmd.Form1.ProgressObject() { Percentage = 20, Message = DateTime.Now.ToString("mm:ss.fff  ") + e.Data + "\n" });
            //08:05.452  08:05.407  16/07/2020  22:58    <DIR>          AndroidStudio
            //08:05.453  08:05.408  28/06/2020  21:03    <DIR>          App
            //08:05.454  08:05.408  21/06/2017  20:50    <DIR>          MP_Upload
            ^^^^^        ^^^^^------- timestamp same as stdOutBuilder.Append()   
            ^^^^^------ arrive after RunProcessAsync() completed                                

            //System.Windows.Forms.Application.DoEvents(); 
            
        }
    };
    processTasks.Add(stdOutCloseEvent.Task);
    ......
}   

// Form1

    public class ProgressObject 
    {
        public int Percentage { get; set; }
        public string Message { get; set; }
    }
    string str2 = "";
    private void updateProgress02(ProgressObject prog)
    {
        //debugPr(prog.Message);
        str2 += (DateTime.Now.ToString("mm:ss.fff  ") + prog.Message);
        rtbError.AppendText(DateTime.Now.ToString("mm:ss.fff  ") + prog.Message);
    }

    private void debugPr(String s)
    {
        System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString("mm:ss.fff  ") + s);   // Output will be in Visual Studio debug window or Dbgview.exe
    }

    string str = "";
    public void updateProgress01(string msg)
    {
        str += (DateTime.Now.ToString("mm:ss.fff  ") + msg );
        progressBar1.Value = progressBar1.Value + 1;
        debugPr(""+progressBar1.Value);
    }

    private void btnShow_Click(object sender, EventArgs e)
    {
        rtbOutput.AppendText("\n\n"+DateTime.Now.ToString("mm:ss.fff  ") + "\n\nm_SynchronizationContext.Post\n");
        rtbOutput.AppendText(str);
        rtbOutput.AppendText("\n\nprogress.Report\n");
        rtbOutput.AppendText(str2);
    }
            
    private void btnStart_Click(object sender, EventArgs e)
    {
        debugPr("ProcessAsyncHelper03");
        ProcessAsyncHelper03 ph = new ProcessAsyncHelper03();
        Task<ExecuteDosCmd.ProcessAsyncHelper03.Result> task3 = ph.RunProcessAsync(psi, new Progress<ProgressObject>(updateProgress02), null, 2000);
        rtbOutput.Text = task3.Result.StdOut;
        rtbError.AppendText(task3.Result.StdErr);
        rtbError.AppendText("\nExitCode: " + task3.Result.ExitCode +"\n\n");
    }


person user3660333    schedule 18.07.2020    source источник
comment
Не блокировать асинхронный код – - Удалите все эти вещи: rtbOutput.Text = task3.Result.StdOut;. Почему вы смешиваете SynchronizationContext и Progress‹T›? Это для теста? См. несколько простых примеров здесь.   -  person Jimi    schedule 18.07.2020
comment
Вы можете сделать эти обработчики событий (как btnStart_Click) async. Или запустить задачу.   -  person Jimi    schedule 18.07.2020
comment
@Jimi Это тест, я хочу найти способ получить вывод в реальном времени в асинхронной задаче для процесса вне задачи.   -  person user3660333    schedule 19.07.2020
comment
@Jimi Я добавил асинхронность в private void btnShow_Click (отправитель объекта, EventArgs e) в private async void btnShow_Click (отправитель объекта, EventArgs e), но получил тот же результат.   -  person user3660333    schedule 19.07.2020
comment
Если вы тестируете выходные данные процесса, вам на самом деле не нужны задачи: процесс создает события, которые, конечно же, асинхронны. Если вы хотите использовать задачу, то вы, как уже упоминалось и как вы должны были прочитать из поста, на который я дал ссылку, не можете заблокировать (используйте Result). Измените свою задачу на общедоступную async Task RunProcessAsync(int processId, IProgress<ProgressObject> progress) { }, используйте только объект Prograss<T> для отчета о ходе выполнения (вы не используете другие параметры, передайте Process.Id, чтобы указать процесс, который вы хотите протестировать, или его имя, в зависимости от того, как вы хотите его обработать).   -  person Jimi    schedule 19.07.2020
comment
Сделайте обработчик btnStart_Click async и await RunProcessAsync(), передав объект Progress<ProgressObject>, который вы создали заранее.   -  person Jimi    schedule 19.07.2020