Quelle est la bonne façon de combiner long tâches en cours d'exécution avec async / await modèle?

J'ai une "Haute Précision" classe timer que j'ai besoin pour être en mesure de démarrer, arrêter, & mettre en pause /reprendre. Pour ce faire, je suis le lien entre un couple de différents exemples que j'ai trouvé sur internet, mais je ne suis pas sûr si je suis à l'aide de Tâches avec asnyc /vous attendent correctement.

Voici mon code:

//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();
}
}
}

Quelqu'un peut veuillez jeter un oeil et me donner quelques conseils sur la façon de savoir si je suis en train de faire cela correctement?

Mise à JOUR

J'ai essayé de modifier mon code par Noseratio les commentaires ci-dessous, mais je ne peux toujours pas comprendre la syntaxe. Chaque tentative de passer la ExecuteAsync() méthode pour TaskFactory.StartNew ou Tâche.Exécuter, provoque une erreur de compilation comme suit:

"L'appel est ambigu entre les méthodes suivantes ou propriétés: TaskFactory.StartNew(Action, CancellationToken...) et TaskFactory.StartNew<Tâche>(Func<Tâche>, CancellationToken...)".

Enfin, est-il un moyen de spécifier le LongRunning TaskCreationOption sans avoir à fournir un 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);
}

Mise à JOUR 2

Je pense que j'ai trouvé, mais pas encore sûr de la syntaxe correcte. Serait-ce la bonne façon de créer de la tâche, de sorte que le consommateur /code d'appel se poursuit, avec la tâche de filature et de départ sur un nouveau thread asynchrone?

_task = Task.Run(async () => await ExecuteAsync, _cancelSource.Token);
//**OR**
_task = Task.Factory.StartNew(async () => await ExecuteAsync, _cancelSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
En passant async () => await ExecuteAsync lambda à Task.Factory.StartNew ne résout pas le problème que j'ai décrit dans le #1. Essentiellement, ça change rien. Découvrez une mise à jour de ma réponse pour un exemple de la syntaxe correcte et logique.
En fait, maintenant que vous avez changé le type de retour de ExecuteAsync à Task, en passant async () => await ExecuteAsync lambda à Task.Factory.StartNew, mais c'est redondant. Il suffit de passer ExecuteAsync et ne task.Unwrap sur le Task<Task> objet renvoyé par Task.Factory.StartNew.

OriginalL'auteur Joshua Barker | 2013-11-28