Is sending messages on go channels a guarantee that they are not blocked?

To assess whether go is a possible option for an audio / video application, I would like to know if messaging in progress satisfies any non-blocking progress guarantees (no obstacles, no locks or no wait). In particular, the following scenarios apply:

Sole manufacturer single manufacturer:

Two streams communicate using a common channel. Thread A performs only asynchronous send, thread B performs only asynchronous send. Suppose the OS scheduler decides to interrupt thread A at the “worst possible moment” for an indefinite time. Is thread B guaranteed to complete the receive operation in a limited number of processor cycles, or is there a (theoretical) possibility that thread A can put the channel in a state in which thread B must wait for the OS to resume thread A?

Several manufacturers:

Multiple streams A1, A2, A3, ... interact with one or more other streams using a common channel. Ai threads only perform asynchronous submissions. Assume that A2, A3, ... are suspended by the OS scheduler at the “worst possible moment” for an indefinite period of time. Is thread A1 still a guarantee to complete the send operation in a limited number of processor cycles? Suppose further that each thread only wants to do one dispatch. If the program has been running long enough (with a “malicious” scheduler that potentially starves some threads or interrupts and resumes threads at the “worst possible moment”), is at least one transmission guaranteed to succeed?

I am not interested in typical scenarios here, but rather the worst guarantees. See the Non-Blocking Algorithm (Wikipedia) for more information on obstruction, lock, and wait algorithms.

+8
go nonblocking lock-free channel
source share
4 answers

The Go memory model does not require sending and receiving non-blocking ones, and the current runtime implementation blocks the channel for send and recv . This means, for example, that you can starve in send or receive mode if the OS scheduler interrupts another thread that starts another processing program that tries to send or receive on the same channel while it has already acquired a channel lock.

So the answer, unfortunately, is no : (

(unless someone overrides parts of the runtime using non-blocking algorithms).

+4
source share

Normal sending and receiving are blocking operations by definition. You can do a non-blocking send or receive using the select statement:

 select { case ch <- msg: default: } 

(Getting is very similar, just replace the case statement.)

Transmission is only performed when there is room in the channel buffer. Otherwise, the default case is triggered. Note that inside the mutex is still used (if I read the code correctly).

+9
source share

You ask if the operation is a guarantee to complete within a limited number of cycles, which, of course, is not a consideration of the design for this language (or most basic operating systems).

If run in a single thread, then Go uses joint multitasking between goroutines. Therefore, if one routine never gives in, then another will never work. If your program works with multiple threads (as set by GOMAXPROCS ), you can run multiple goroutines at the same time, in which case the OS manages scheduling between threads. However, in no case is there a guaranteed upper bound on the time until the function call is completed.

Note that the cooperative nature of goroutines gives you some control over the execution of planning — that is, procedures are never unloaded. Until you give in, you will retain control of the flow.

Regarding lock behavior, see Language Specification :

The capacity in the number of elements sets the size of the buffer in the channel. If the capacity is greater than zero, the channel is asynchronous: communication operations are successful without blocking, if the buffer is not full (sent) or empty (receives), and the elements are received in the order in which they are sent. If the capacity is zero or absent, the connection will be successful only when both the sender and the receiver are ready.

Note that non-blocking send and receive on channels can be performed using the select syntax already mentioned.

+1
source share

Gorutas have no channels or values ​​sent to them. Thus, the execution status of the goroutine that sent / sends values ​​in the channel does not affect the ability of other goroutines to send or receive values ​​on this channel, unless the channel buffer is full, in which case all sendings will be blocked until the appropriate reception occurs, or the buffer is empty, in which case all received will be blocked until the corresponding sending appears.

Since goroutines use collaborative scheduling (they must be inferior to the scheduler either through a channel operation, or syscall, or by explicitly calling runtime.Gosched() ), it is not possible for the goroutine to be interrupted at the “worst possible time”. Gorutin can never go out, and in this case he can endlessly bind a thread. If you have only one thread of execution, then your other goroutines will never be scheduled. It is possible, but statistically unlikely, that goroutine was never planned. However, if all but one goroutines are blocked during sending or receiving, then the remaining goroutine should be planned.

You can come to a standstill. If I have two goroutines running:

 func Goroutine(ch1, ch2 chan int) { i := <-ch1 ch2 <- i } ... ch1, ch2 := make(chan int), make(chan int) go Goroutine(ch1, ch2) go Goroutine(ch2, ch1) 

Then, as should be obvious, both goroutines are waiting for the other to send a value that will never happen.

0
source share

All Articles