8
votes

Le message passe-t-il via des canaux allés à être non bloqués?

Pour déterminer si Go est une option possible pour une application audio / vidéo, j'aimerais savoir si le message qui passe en go est satisfait à toutes les garanties de progrès non bloquantes (sans obstruction, sans verrouillage ou sans attente. ). En particulier, les scénarios suivants sont pertinents:

producteur unique consommateur unique:

Deux threads communiquent à l'aide d'un canal partagé. Le fil a seulement des envois asynchrones, le fil b ne reçoit que l'asynchrone. Supposons que le planificateur du système d'exploitation décide d'interrompre le fil a le "pire moment possible" pour une durée indéterminée. Le fil b garantie-t-il une opération de réception dans un nombre limité de cycles de processeur ou est une possibilité (théorique) que le filetage A peut placer le canal dans un état où le thread b doit attendre que le système d'exploitation reprenne le fil A?

producteurs multiples:

Plusieurs threads A1, A2, A3, ... communiquent avec un ou plusieurs autres threads à l'aide d'un canal partagé. Les threads AI ne font que des envois asynchrones. Supposons que A2, A3, ... Sont suspendus par le planificateur du système d'exploitation au «pire moment possible» pour une durée indéterminée. Le fil A1 est-il toujours garanti de terminer une opération d'envoi dans un nombre délimité de cycles CPU? Supposons que chaque fil ne veut que faire un envoi. Si le programme est suffisamment long (avec un planificateur "malveillant" qui préconise certains threads ou interrompt et reprend les fils au "pire moment possible"), est au moins un envoi garanti pour réussir?

Je ne suis pas tellement intéressé par des scénarios typiques ici, mais plutôt des garanties pillantes. Voir Algorithme non bloquante (Wikipedia) pour plus de détails sur obstruction-, verrouillage et attente algorithmes gratuits.


1 commentaires

Premièrement, le temps d'exécution GO n'est pas en temps réel (il s'agit d'une langue collectée à une autre), ni le système d'exploitation que vous utilisez. En outre, «non bloquant» signifie que le canal vous enverra lorsque le récepteur n'est pas plein, bloquez une fois, ou n'envoyez pas le message (auquel cas, le message est abandonné ou placé localement).


4 Réponses :


10
votes

Les envois normaux et reçus sont des opérations de blocage par définition. Vous pouvez effectuer un envoi non bloquant ou recevoir à l'aide d'une instruction SELECT:

select {
case ch <- msg:
default:
}


3 commentaires

Je pense qu'il pourrait y avoir un choc de terminologie concernant le terme "non-blocage". Quand je dis "asynchrone", je veux dire "non bloquant" dans le sens de Go. Ma vraie question est que je puisse écrire des algorithmes non bloquants à l'aide d'un envoi / reçus de Go non bloquants. Ce ne serait pas le cas par ex. Si un (Go non bloquant) Envoyer / Recevoir a provoqué le compilateur GO pour verrouiller le canal à l'aide d'un mutex lors de l'exécution de l'envoi / réception.


Je vois. Il me semble que l'exécution utilise toujours des mutiles dans un envoi ou une réception non bloquante. Consultez les fonctions de Chansend et ChanRecv en SRC / PKG / Runtime / Chan.c si vous êtes intéressé par les détails.


Merci pour le pointeur! Malheureusement, ce n'est pas le code le plus lisible ... Je vois si je peux le déchiffrer plus tard.



1
votes

Vous demandez si une opération est garantie de remplir dans un nombre limité de cycles, ce qui n'est bien sûr pas une contrepartie de conception pour cette langue (ou la plupart des OSES sous-jacents).

Si exécutée dans un seul fil, allez utiliser Coopérative multitâche entre les goroutines. Donc, si une routine ne cède jamais, l'autre ne courra jamais. Si votre programme s'exécute sur plusieurs threads (comme défini par gomaxprocs ), vous pouvez exécuter plusieurs gorouts simultanément, auquel cas l'OS contrôle la planification entre les threads. Cependant, dans aucun cas, il n'y a pas une limite supérieure garantie à la fin de l'achèvement d'un appel de la fonction.

Notez que la nature coopérative des goroutines vous donne une certaine quantité de contrôle sur l'exécution de planification - c'est-à-dire que les routines ne sont jamais préemptées. Jusqu'à ce que vous cédez, vous conservez le contrôle du fil.

comme pour le comportement de blocage, voir Spécification de la langue :

La capacité, en nombre d'éléments, définit la taille du tampon dans le canal. Si la capacité est supérieure à zéro, le canal est asynchrone: les opérations de communication réussissent sans blocage si le tampon n'est pas plein (envoie) ou non vide (reçoit) et les éléments sont reçus dans l'ordre de leur envoi. Si la capacité est zéro ou absente, la communication ne réussit que lorsque l'expéditeur et le récepteur sont prêts.

Notez que les envois non bloquants et reçoivent sur des canaux peuvent être accomplis à l'aide de la syntaxe de sélectionner déjà mentionnée.


0 commentaires

0
votes

Les goroutines ne possèdent pas de canaux ni des valeurs qui leur sont envoyées. Donc, l'état d'exécution d'un goroutin qui a envoyé / envoi de valeurs sur une chaîne n'a aucun impact sur la capacité des autres goroutines à envoyer ou à recevoir des valeurs sur ce canal, à moins que le tampon du canal soit plein, auquel cas tous les envois ne bloquent jusqu'à ce qu'une réception correspondante se produise ou que le tampon est vide, auquel cas tous les reçus bloqueront jusqu'à ce qu'il y ait un envoi correspondant.

Parce que les gorouts utilisent la planification de la coopérative (elles doivent céderez au planificateur, soit à travers une opération de canal, Syscall, ou un appel explicite à runtime.gosched () ), il est impossible qu'un goroutine soit interrompu au "pire temps possible". Il est possible que le goroutine ne cède jamais, auquel cas, il pourrait lier un fil indéfiniment. Si vous n'avez qu'un seul fil d'exécution, vos autres gorouts ne seront jamais programmés. C'est possible, mais statistiquement improbable, pour un goroutine de ne jamais être programmé. Toutefois, si toutes les gorouts mais que l'une est bloquée sur des envois ou reçoit, le goroutine restant doit être planifié.

Il est possible d'obtenir une impasse. Si j'ai deux gorouts exécutant: xxx

puis, comme cela devrait être apparent, les deux goroutines attendent que l'autre envoie une valeur, qui n'arrivera jamais.


0 commentaires

4
votes

Le modèle de mémoire Go ne nécessite pas d'envoi et ne reçoit pas de blocage, et Le courant Runtime implémentation verrouille le canal pour envoyer et recv . Cela signifie, par exemple, il est possible de freiner une routine d'envoi ou de réception si le planificateur d'exploitation interrompt un autre thread exécutant une autre routine Go-routine qui tente d'envoyer ou de recevoir sur le même canal lorsqu'il a déjà acquis la serrure du canal. .

La réponse est donc malheureusement non : (

(sauf si une personne réimplémente les parties du temps d'exécution à l'aide d'algorithmes non bloquants).


0 commentaires