【发布时间】:2013-12-14 04:57:18
【问题描述】:
我有一个“高精度”计时器类,我需要能够启动、停止和暂停/恢复。为此,我将我在 Internet 上找到的几个不同示例结合在一起,但我不确定我是否正确使用了带有 asnyc / await 的 Tasks。
这是我的相关代码:
//based on http://haukcode.wordpress.com/2013/01/29/high-precision-timer-in-netc/
public class HighPrecisionTimer : IDisposable
{
Task _task;
CancellationTokenSource _cancelSource;
//based on http://blogs.msdn.com/b/pfxteam/archive/2013/01/13/cooperatively-pausing-async-methods.aspx
PauseTokenSource _pauseSource;
Stopwatch _watch;
Stopwatch Watch { get { return _watch ?? (_watch = Stopwatch.StartNew()); } }
public bool IsPaused
{
get { return _pauseSource != null && _pauseSource.IsPaused; }
private set
{
if (value)
{
_pauseSource = new PauseTokenSource();
}
else
{
_pauseSource.IsPaused = false;
}
}
}
public bool IsRunning { get { return !IsPaused && _task != null && _task.Status == TaskStatus.Running; } }
public void Start()
{
if (IsPaused)
{
IsPaused = false;
}
else if (!IsRunning)
{
_cancelSource = new CancellationTokenSource();
_task = new Task(ExecuteAsync, _cancelSource.Token, TaskCreationOptions.LongRunning);
_task.Start();
}
}
public void Stop()
{
if (_cancelSource != null)
{
_cancelSource.Cancel();
}
}
public void Pause()
{
if (!IsPaused)
{
if (_watch != null)
{
_watch.Stop();
}
}
IsPaused = !IsPaused;
}
async void ExecuteAsync()
{
while (!_cancelSource.IsCancellationRequested)
{
if (_pauseSource != null && _pauseSource.IsPaused)
{
await _pauseSource.Token.WaitWhilePausedAsync();
}
// DO CUSTOM TIMER STUFF...
}
if (_watch != null)
{
_watch.Stop();
_watch = null;
}
_cancelSource = null;
_pauseSource = null;
}
public void Dispose()
{
if (IsRunning)
{
_cancelSource.Cancel();
}
}
}
任何人都可以看看并提供一些关于我是否正确执行此操作的指示吗?
更新
我已经尝试根据下面的 Noseratio 的 cmets 修改我的代码,但我仍然无法弄清楚语法。每次尝试将 ExecuteAsync() 方法传递给 TaskFactory.StartNew 或 Task.Run 都会导致编译错误,如下所示:
“以下方法或属性之间的调用不明确:TaskFactory.StartNew(Action, CancellationToken...) 和 TaskFactory.StartNew
最后,有没有一种方法可以指定 LongRunning TaskCreationOption 而无需提供 TaskScheduler?
async **Task** ExecuteAsync()
{
while (!_cancelSource.IsCancellationRequested)
{
if (_pauseSource != null && _pauseSource.IsPaused)
{
await _pauseSource.Token.WaitWhilePausedAsync();
}
//...
}
}
public void Start()
{
//_task = Task.Factory.StartNew(ExecuteAsync, _cancelSource.Token, TaskCreationOptions.LongRunning, null);
//_task = Task.Factory.StartNew(ExecuteAsync, _cancelSource.Token);
//_task = Task.Run(ExecuteAsync, _cancelSource.Token);
}
更新 2
我想我已经缩小了范围,但仍然不确定正确的语法。这是否是创建任务的正确方法,以便消费者/调用代码继续执行,任务启动并在新的异步线程上启动?
_task = Task.Run(async () => await ExecuteAsync, _cancelSource.Token);
//**OR**
_task = Task.Factory.StartNew(async () => await ExecuteAsync, _cancelSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
【问题讨论】:
-
将
async () => await ExecuteAsynclambda 传递给Task.Factory.StartNew并不能解决我在#1 中描述的问题。从本质上讲,它没有任何改变。查看我的答案的更新以获取正确语法和逻辑的示例。 -
实际上,既然您已经将
ExecuteAsync的返回类型更改为Task,将async () => await ExecuteAsynclambda 传递给Task.Factory.StartNew就可以了,但它是多余的。只需传递ExecuteAsync并在Task.Factory.StartNew返回的Task<Task>对象上执行task.Unwrap。
标签: c# xamarin.ios task-parallel-library async-await long-running-processes