没有任务等待时如何适当延迟
How to properly delay when there is no task to wait for
我有一个任务正在等待 属性 设置为真(= 已完成)。我收到 属性 值更改的方式是通过 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;
}
}
Windows 中的计时器的分辨率约为16 毫秒,因此无法精确实现低于 16 毫秒的任何延迟。这适用于任何计时器 - .NET 计时器只是 Windows 本机计时器的包装器。
创建自定义 TaskCompletionSource<T>
和 return 一个可以等待的 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();
我有一个任务正在等待 属性 设置为真(= 已完成)。我收到 属性 值更改的方式是通过 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;
}
}
Windows 中的计时器的分辨率约为16 毫秒,因此无法精确实现低于 16 毫秒的任何延迟。这适用于任何计时器 - .NET 计时器只是 Windows 本机计时器的包装器。
创建自定义 TaskCompletionSource<T>
和 return 一个可以等待的 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();