Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unbuffered channel operations with select at both ends never happen #43

Open
cleatoma opened this issue Jun 29, 2015 · 2 comments
Open

Comments

@cleatoma
Copy link

This go program works:

package main

import "fmt"
import "time"

func main() {
    ch := make(chan int)
    ch2 := make(chan int)
    ch3 := make(chan int)
    go func() {
        select {
            case i := <-ch:
                fmt.Println("Received", i, "from main channel")
            case i := <-ch2:            
                fmt.Println("Received", i, "from ch2, how odd")
            }
    }()
    go func() {
        select {
            case ch <- 1:
                fmt.Println("Written 1 to main channel")
            case ch3 <- 1:
                fmt.Println("Written 1 to ch3, how odd")        
            }
    }()
    time.Sleep(100)
}

The runtime figures out which channel operation can proceed, and it does:

Written 1 to main channel
Received 1 from main channel

The equivalent goless program doesn't work:

import gevent
import goless

ch = goless.chan()
ch2 = goless.chan()
ch3 = goless.chan()

def read():
    cases = [goless.rcase(ch), goless.rcase(ch2)]
    case, val = goless.select(cases)
    print case, val

def write():
    cases = [goless.scase(ch, 1), goless.scase(ch3, 1)]
    case, val = goless.select(cases)
    print case, val

goless.go(read)
goless.go(write)

gevent.sleep(1)

Nothing is printed.

From checking the source code, it looks like performing a select never adds anything to the channels which are ready to read or to write, only an unconditional ch.send() or ch.recv() will do that, so it's not possible for two selects on either end of an unbuffered channel to ever proceed.

This is a pretty big departure from how unbuffered channels work in go. It seems that this is either a bug to be fixed, or should be mentioned in the documentation.

@rgalanakis
Copy link
Owner

Hi cleatoma, you're right, this is definitely not working correctly.
It should be pretty easy to reproduce this as a test case, if you want to try it out?
I don't really have the time to fix this right now as I'm not using goless actively anymore, but would happily review and merge any PRs.

@navytux
Copy link

navytux commented Jun 26, 2018

I had to port recently some of my go code to python. And for that I needed properly working select. Knowing about goless I initially wanted to use it, but in the end came up with my own channels implementation:

https://pypi.org/project/pygolang/
https://lab.nexedi.com/kirr/pygolang

It is currently not very fast, but should be working correctly including select - select sends for synchronous channels:

https://lab.nexedi.com/kirr/pygolang/blob/812e7ed7/golang/golang_test.py#L282
https://lab.nexedi.com/kirr/pygolang/blob/812e7ed7/golang/__init__.py#L372

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants