【问题标题】:How to properly delay when there is no task to wait for没有任务等待时如何正确延迟
【发布时间】:2019-10-05 21:38:34
【问题描述】:

我有一个任务正在等待将属性设置为 true(= 已完成)。我接收该属性值更改的方式是通过 EventHandler(确切地说是System.Diagnostics.Process.OutputDataReceived - 它不断读取另一个进程的输出,直到提供正确的输出)。然而,一直检查财产感觉有些低效。我尝试添加一个滴答的小延迟,因为我相信如果这样可以节省 CPU 时间,我可以让自己等待,但我读到 .NET 与小数毫秒的斗争。我可以改进这段代码吗?

private ConcurrentBag<string> _allMessages = new ConcurrentBag<string>();

public OutputRetriever()
{
    var process = new System.Diagnostics.Process();
    ...
    process.OutputDataReceived += OutputDataReceived;
    process.Start();
}

public async Task<string[]> GetAllOutput()
{   
    while (!IsCompleted)
    {
        // how to properly wait here?
        // await Task.Delay(TimeSpan.FromTicks(1)); // is this ok?
    }
    return _allMessages.ToArray();
}

private void ConsoleDataReceived(object sender, DataReceivedEventArgs e)
{
    _allMessages.Add(e?.Data);
    if (e?.Data == "success")
    {
        IsCompleted = true;
    }
}

【问题讨论】:

    标签: c# asynchronous process task delay


    【解决方案1】:

    Windows 中的计时器的分辨率约为。 16 ms,因此任何低于 16 ms 的延迟都无法精确实现。这适用于任何计时器 - .NET 计时器只是 Windows 本机计时器的包装器。

    创建一个自定义的TaskCompletionSource&lt;T&gt; 并返回一个可以等待的Task,而不是在循环中忙于等待。

    class OutputRetriever
    {
        private readonly ConcurrentBag<string> _allMessages = new ConcurrentBag<string>();
    
        private readonly TaskCompletionSource<string[]> _taskSource
            = new TaskCompletionSource<string[]>();
    
        // Note: this method is not async anymore
        public Task<string[]> GetAllOutput()
        {
            // We just return a task that can be awaited
            return _taskSource.Task;
        }
    
        void ConsoleDataReceived(object sender, DataReceivedEventArgs e)
        {
            _allMessages.Add(e?.Data);
            if (e?.Data == "success")
            {
                // Here we notify that the task is completed by setting the result
                _taskSource.SetResult(_allMessages.ToArray());
            }
        }
    }
    

    现在客户可以像往常一样简单地等待结果:

    var receiver = new OutputReceiver();
    string[] messages = await receiver.GetAllOutput();
    

    【讨论】:

    • 这正是我想要的。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-26
    • 1970-01-01
    • 2019-07-27
    • 2015-09-14
    相关资源
    最近更新 更多