Async tâches et des verrous
J'ai une liste d'éléments qui doivent être mis à jour par les deux processus. Premier, c'est le thread de l'INTERFACE utilisateur (contrôlée par l'utilisateur), le second est un processus d'arrière-plan qui récupère les informations à partir d'un service web.
Depuis ce second processus est dépendant des e/S, il semble approprié pour async tâches. Cela m'amène à quelques questions:
- Depuis async tâches ne fonctionne pas sur des threads séparés, il semble que je n'ai pas besoin de tout type de serrure lorsque la mise à jour de cette liste, de droite?
- D'autre part, peut-on supposer que async tâches ne sera jamais sur des threads séparés?
- Je parle d'une application Windows Forms. Peut-être que dans l'avenir je veux l'exécuter comme une application console. Autant que je sache, dans les applications de console Async les tâches s'exécutent sur des threads séparés. Quelle est la préférée de l'idiome de poser une tâche si elle est en cours d'exécution sur un thread séparé? De cette façon, je peux établir une serrure si nécessaire.
- Le fait que je ne sais pas si j'ai vraiment besoin d'un verrou qui me fait me demander si ce n'est le meilleur ou non. Serait-il judicieux de coller à
Task.Run()
même pour ce genre de IO lié code?
Et par processus vous voulez dire réel distinct de processus de windows, ou quoi? Si oui, comment partagez-vous votre liste entre les processus? Je suppose qu'il n'est pas vraiment un processus, mais vous devez vous assurer que... Est-ce quelque chose que l'utilisateur commence par l'interaction avec l'INTERFACE utilisateur, c'est quelque chose qui fonctionne basé sur une minuterie? C'est très important d'informations.
Il ne fonctionne pas sur une minuterie. C'est juste une fonction qui met à jour une liste très longue. Depuis la mise à jour de chaque élément comporte la connexion à un service web, la mise à jour de la liste complète peut prendre quelques secondes, voire quelques minutes.
Il ne fonctionne pas sur une minuterie. C'est juste une fonction qui met à jour une liste très longue. Depuis la mise à jour de chaque élément comporte la connexion à un service web, la mise à jour de la liste complète peut prendre quelques secondes, voire quelques minutes.
OriginalL'auteur sapito | 2015-01-02
Vous devez vous connecter pour publier un commentaire.
Il n'y a pas de garantie que l'on n'utilise pas
Task.Run
et le marquage de sa méthodeasync
. IO lié async tâches sont plus susceptibles pas en utilisant une sorte de fil en coulisses, mais ce n'est pas toujours le cas. Vous ne devriez pas compter sur l'exactitude de votre code. Vous pouvez vous assurer que votre code s'exécute sur le thread d'INTERFACE utilisateur en l'enveloppant avec un autreasync
méthode qui n'utilise pas deConfigureAwait(false)
. Vous pouvez toujours utiliser la concurrente de collections de données dans le cadre. Peut-être unConcurrentBag
ou unBlockingCollection
pouvez suite à vos besoins.Qui est incorrect.
async
opérations en vis à vis ne courent pas séparées sur les threads seulement parce qu'ils sont dans une application console. Il suffit de mettre, la valeur par défautTaskScheduler
dans une application console est la valeur par défautThreadPoolTaskScheduler
, qui file toute poursuite sur un pool de threads thread, comme une console n'a pas une telle entité appelée un thread d'interface utilisateur. Généralement, il est tout au sujet de SynchronizationContextCertainement pas. Le fait que vous ne savez pas, c'est la raison pour laquelle vous posté cette question, et la raison pour laquelle nous essayons d'aider.
Il n'est pas nécessaire d'utiliser un pool de threads thread pour faire async IO. Le point de l'ensemble de async IO est le fait que vous pouvez libérer le thread appelant à faire IO processus de travail de plus en alors que la demande est en cours de traitement.
async
I/O doit être pur (donc thread-safe), et lePresenter/Controller/whatever
doit être thread-dangereux, et demande le rappel à exécuter sur le thread de l'INTERFACE utilisateur. Toutefois, en ce qui concernelock
ing. Le point deasync
de programmation est de le rendre plus facile d'écrire à thread unique de blocage (lock) des programmes gratuits.J'aime cette réponse, mais je pense que Aron a fait un bon point. @Aron: avez-vous suggérons d'utiliser
Control.Invoke
afin de mettre à jour la liste et l'INTERFACE utilisateur?Si la collecte de données est lié à des éléments de l'INTERFACE utilisateur, alors je suis d'accord et en fait, les OP n'ont pas le choix dans ce cas. Sinon, je vois pas de raison de se limiter vous-même à le thread d'INTERFACE utilisateur et d'avoir à utiliser l'INTERFACE utilisateur de la boucle de message d'accéder à une collection.
Itzchakov: en fait, la collection est "partie liée". Chaque fois que j'ai mise à jour de l'un de ses éléments, que je doit vérifier si elle appartient à l'ensemble qui est affiché. Si elle l'est, je dois aussi mettre à jour l'INTERFACE utilisateur. Je pense qu'il fait sens pour exécuter toutes les mises à jour sur le thread de l'INTERFACE utilisateur, même si tous les éléments sont liés.
Si elle fait sens dans ce cas particulier, allez-y 🙂 Mais je dirais peut-être pas la meilleure solution pour les cas où les éléments de l'INTERFACE utilisateur ne sont pas impliqués.
OriginalL'auteur Yuval Itzchakov
Assez vrai. Cette approche fonctionne bien si vous suivez un schéma fonctionnel (c'est à dire, chaque opération en arrière-plan sera retour de son résultat, plutôt que la mise à jour de données partagées). Donc, quelque chose comme ce sera beau travail:
Dans ce cas, il n'a pas d'importance comment
GetItemAsync
est mis en œuvre. Il peut utiliserTask.Run
ouConfigureAwait(false)
tout ce qu'elle veut -BackgroundWorkAsync
seront toujours synchronisés avec le thread de l'INTERFACE utilisateur avant d'ajouter l'élément à la collection.Async"tâches" ne pas exécuter à tous. Si c'est confus, j'ai un async intro qui peuvent être utiles.
Chaque méthode asynchrone commence à être exécutée de manière synchrone. Quand il frappe un
await
, c' (par défaut) permet de saisir le contexte actuel et, plus tard, l'utilise pour reprendre l'exécution de la méthode. Donc, ce qui se passe quand il est appelé à partir d'un thread d'INTERFACE utilisateur est que leasync
méthode reprend sur la capture de l'INTERFACE utilisateur contexte. Console applications ne fournissent pas un cadre, de sorte que leasync
méthode reprend sur un thread du pool.Je recommanderais un design qui n'est pas poser de telles filetage questions. Tout d'abord, vous pouvez simplement utiliser une plaine
lock
- ils sont extrêmement vite quand il n'y a pas de conflit:Sinon, vous pouvez documenter que le composant dépend d'un un-à-un-temps contexte, et d'utiliser quelque chose comme
AsyncContext
de mon AsyncEx bibliothèque pour l'application Console.Control.Invoke
à la fois de mettre à jour la liste et l'INTERFACE utilisateur? Je suis conscient qu'il n'est pas nécessaire, mais je pense que ça va rendre le code plus "robuste". Peut-être que dans le futur, quelqu'un peut activer cette async tâche à exécuter sur le pool de threads (Task.Run
), ou lorsque le portage d'une application de console, comme nous n'avons pasControl.Invoke
, le compilateur va nous faire prendre conscience de la question.Pas de. Je recommande à tous de jamais l'utilisation
Control.Invoke
. Un simplelock
devrait suffire.Je comprends votre point pour l'application console. Mais sur Windows Forms, le verrou n'est pas nécessaire (en fait il n'est pas), ou j'ai besoin d'utiliser
Control.Invoke
, parce que, après la mise à jour de la liste, j'ai aussi besoin de mettre à jour l'INTERFACE utilisateur. I. e, pour l'application Windows Forms, avec la serrure, mais pas à l'aide deControl.Invoke
serait incohérent. Mais je vois votre conseil est de ne pas utiliser quoi que ce soit pour l'application WinForms.Je vous recommande de conception pour les cas d'utilisation que vous avez. Si votre cas d'utilisation modifier dans l'avenir, de modifier le code à ce moment.
oui, merci. Je pense que je suis en train de tomber dans la conception de la paralysie. J'ai déjà eu quelques solutions qui devraient fonctionner. Le temps de la mettre en œuvre...
OriginalL'auteur Stephen Cleary
Asyc-await
capture le contexte de synchronisation avant laawait
déclaration puis s'exécute par défaut de la poursuite sur le même contexte après laawait
déclaration. Contexte de synchronisation de thread de l'INTERFACE utilisateur ne sont associés qu'à un fil, donc, dans ce type de scénario vous êtes, vous pourriez vous retrouver toujours la mise à jour de la liste dans le thread de l'INTERFACE utilisateur.Mais si quelqu'un modifie le code pour appeler
ConfigureAwait(false)
d'après un de la, attend la poursuite ne fonctionne pas sur l'origine de contexte de synchronisation et vous pouvez terminer la mise à jour de la liste sur l'un des threads du pool de threads.Notez également que vous ne pouvez pas utiliser
await
à l'intérieur d'unlock
déclaration, mais vous pouvez utiliser unSemapahoreSlim
faire asynchrone attendre au lieu.À mon humble avis c'est beaucoup mieux de simplement utiliser un synchronisé collection plutôt que de s'appuyer sur la liste de cours de mise à jour à partir du même thread.
Vous ne pouvez pas supposer que, l'actuel contexte de synchronisation sera capturé, mais les suites ne peuvent pas toujours s'exécuter.
Je voudrais utiliser un synchronisé collection ou
SempahoreSlim
dans ce cas. Pour l'application de console le pool de threads synchronizationo contexte est utilisé et les continuations pourrait mettre fin à la course à pied sur tout le pool de threads.Il est logique d'utiliser asynchrone-vous attendent pour IO lié code car il ne consommez pas d'un fil.
Je collerais avec l'aide de
async-await
et le changement d'utiliser un thread safe collection ou synchroniser à l'aide deSemaphoreSlim
OriginalL'auteur Ned Stoyanov