代码之家  ›  专栏  ›  技术社区  ›  Andrius NaruÅ¡evičius

当没有任务等待时,如何适当延迟

  •  0
  • Andrius NaruÅ¡evičius  · 技术社区  · 5 年前

    我有一个任务正在等待属性设置为true(=已完成)。我接收属性值更改的方式是通过EventHandler( System.Diagnostics.Process.OutputDataReceived

    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;
        }
    }
    
    1 回复  |  直到 5 年前
        1
  •  1
  •   dymanoid    5 年前

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

    TaskCompletionSource<T> 然后返回一个 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();