Since go is a concurrency program language and use channel
(I use it almost all my code) or something else to synchronous goroutine
.
And I also knew that go use a scheduler to schedule goroutine
which means you should call scheduler
(channel action, runtime.goSche or something else) in each goroutine and guarantee it would be executed.
Above is all my current limited on go
and I use them to design my code.
But I also find it would occurred code blocking in my code. And it is hard to find where cause the block(even use GDB).
Was I miss something?
What else could possible cause the block?
And what things I should make attention?
[EDIT]: OK, since the code of my project is little big. I decide not show standard go
code, just the general idea of the part that may possibly cause the code-blocking. Here are some code pieces of file transmit module in my project:
func(c *client)listenRead() {
for {
_ := websocket.JSON.Receive(c.ws, &package)
switch package.Op {
case fileUpld:
c.fileMan.store <- package.Body
case fileDownld:
c.fileMan.downld <- package.Body
case c.xxx:
...
default:
// bad package.
}
}
}
A client listening and receive message through websocket from another client and then forward the package according to package
's Op
field to different handler, e.g.,fileManager
shows below.
func(fm *fileManager) fileRouter() {
for {
select {
case fs := <-fm.fileUpld:
if window < filesize {
f.Write(fs.content) // client A write to file
window += fs.contSize
} else {
f.close() // close file
}
case fd := fm.downld:
go fm.downldFile(fd)
}
}
}
A fileManger
can receive file pieces and store to server when the chan fileUpld
get data that send from client
. And it can download file when it receive the request
from a client, and it will generate a goroutine
to do the job, which shows below:
func(fm *fileManager) downldFile(fd) {
f := getFile(fd) // get the file that client A write
b := make([]byte, SeqLength)
for {
if convergence < window {
f.Read(b)
// wrap 'b' to package 'p', for send
fm.server.send <- p // send to client B
} else if window < fileSize {
runtime.Goshed()
} else {
// download done.
fm.done <- xx
return
}
}
}
The major idea of my file transmit module is client A want to send a file to client B, and don't want to wait for the acceptance
from client B, which means it will store to server first and client B will get the file later by download from server. But it could be possible that client B download the file while client A uploading a file. So there needs a synchronous between upload and download.
I use three variable to implement this: window, convergence, filesize. When client A uploading(write) file, window will increase it's value that the bytes it writes. And when client B download(read) the file, convergence will increase the bytes that it reads. Write
happens only window < filesize
while read
happens only convergence < window
. Just like:
+-----------+---------------+--------------+
|############|||||||||||||||| |
+-----------+---------------+--------------+
^ ^ ^
| | |
convergence window filesize
I knew this would cause data-race, but it also guarantee that read
won't read the content that write
has not write yet.(BTW:I don't have a solution using channel
to implement it.)
The code-blocking occurs when I try to upload and download the same time(I slow the client A to achieve it). But it have no problem when I set GOMAXPROCS
to 2.