en attente d'une observable
Donc, dans les tristes jours de C# 4.0, j'ai créé le suivant: "WorkflowExecutor" de la classe qui a permis asynchrone de flux de travail dans le thread GUI par le piratage en IEnumerable du "taux de retour" les suites à attendre des observables. Ainsi, le code suivant devrait, à button1Click, il suffit de lancer un flux de travail simple qui met à jour le texte, attend que vous cliquez sur le bouton 2, et des boucles d'après 1 seconde.
public sealed partial class Form1 : Form {
readonly Subject<Unit> _button2Subject = new Subject<Unit>();
readonly WorkflowExecutor _workflowExecutor = new WorkflowExecutor();
public Form1() {
InitializeComponent();
}
IEnumerable<IObservable<Unit>> CreateAsyncHandler() {
Text = "Initializing";
var scheduler = new ControlScheduler(this);
while (true) {
yield return scheduler.WaitTimer(1000);
Text = "Waiting for Click";
yield return _button2Subject;
Text = "Click Detected!";
yield return scheduler.WaitTimer(1000);
Text = "Restarting";
}
}
void button1_Click(object sender, EventArgs e) {
_workflowExecutor.Run(CreateAsyncHandler());
}
void button2_Click(object sender, EventArgs e) {
_button2Subject.OnNext(Unit.Default);
}
void button3_Click(object sender, EventArgs e) {
_workflowExecutor.Stop();
}
}
public static class TimerHelper {
public static IObservable<Unit> WaitTimer(this IScheduler scheduler, double ms) {
return Observable.Timer(TimeSpan.FromMilliseconds(ms), scheduler).Select(_ => Unit.Default);
}
}
public sealed class WorkflowExecutor {
IEnumerator<IObservable<Unit>> _observables;
IDisposable _subscription;
public void Run(IEnumerable<IObservable<Unit>> actions) {
_observables = (actions ?? new IObservable<Unit>[0]).GetEnumerator();
Continue();
}
void Continue() {
if (_subscription != null) {
_subscription.Dispose();
}
if (_observables.MoveNext()) {
_subscription = _observables.Current.Subscribe(_ => Continue());
}
}
public void Stop() {
Run(null);
}
}
La partie intelligente de l'idée, à l'aide de "rendement" des continuations pour faire le travail asynchrone, a été prise de Daniel Earwicker de AsyncIOPipe idée: http://smellegantcode.wordpress.com/2008/12/05/asynchronous-sockets-with-yield-return-of-lambdas/, puis j'ai ajouté le réactif cadre sur le dessus de cela.
Maintenant, je vais avoir de la difficulté à réécrire cette aide de la fonctionnalité async en C# 5.0, mais il semble que cela devrait être une simple chose à faire. Quand je convertir des observables de tâches, ils ont exécuté qu'une fois et la boucle while se bloque la 2ème fois. Tous aider à corriger, ce serait super.
Tout ce que dit/demandé, ce qui ne l'async/await mécanisme de me donner que le WorkflowExecutor ne l'est pas? Est-ce que je peux faire avec async/await que je ne peux pas le faire (étant donné qu'une même quantité de code) avec le WorkflowExecutor?
- Comment avez-vous fait exactement que la conversion à l'
Task
s? Comment fonctionne le look crash? - Et
await
a beaucoup d'avantages sur ce genre d'asynchronie, mais l'une des grandes différences est que le retour de la awaitables. E. g.string s = await client.DownloadStringAsync(url);
.
Vous devez vous connecter pour publier un commentaire.
Comme vous l'avez remarqué, la Tâche est beaucoup en une seule fois l'utilisation de chose, par opposition à l'observation du "flux d'évènements". Une bonne façon de penser de cela (à mon humble avis) est la 2x2 sur le graphique de Rx de l'équipe de post à ce sujet 2.0 Beta:
En fonction des circonstances (une seule fois par rapport aux "flux" des événements), en gardant Observable pourrait faire plus de sens.
Si vous pouvez monter jusqu'à la Réactif 2.0 Beta, alors vous pouvez 'attendre' observables avec qui. Par exemple, ma propre tentative de 'async/await' (approximative) de la version de votre code serait:
Task
est un temps de l'utiliser, mais vous pouvezawait
choses qui ne sont pasTask
s. Donc, il devrait être possible de créer un awaitable que peut représenter l'ensemble de laIObservable<T>
, pas un seul élément.Que James mentionné précédemment, vous pouvez attendre un IObservable<T> séquence, à partir de Rx v2.0 Beta. Le comportement est de retour le dernier élément (avant le OnCompleted), ou de jeter le OnError qui a été observée. Si la séquence contient pas d'éléments, vous obtiendrez une exception InvalidOperationException out.
Avis en utilisant cela, vous pouvez obtenir tous les autres comportements souhaités:
Vous pouvez faire encore plus de choses de fantaisie, comme le calcul du résultat d'une agrégation, mais respectez les valeurs intermédiaires en utilisant Faire et d'Analyse:
ToTask
également se comporte comme cela. Il faudra faire_tcs.TrySetException(new InvalidOperationException(Strings_Linq.NO_ELEMENTS));
. Ce n'est pas évident, j'ai été chercher mes.First*
appels pendant des heures avant de se rendre compte que les observables se lançait cela dans un scénario qui était prévu par moi.