mirror of https://github.com/golang/go.git
section on service multiplexing
R=gri DELTA=75 (57 added, 4 deleted, 14 changed) OCL=15394 CL=15398
This commit is contained in:
parent
1841f3114e
commit
6820196b75
|
|
@ -51,7 +51,10 @@ program that doesn't depend on "print()":
|
||||||
--PROG progs/helloworld2.go
|
--PROG progs/helloworld2.go
|
||||||
|
|
||||||
This version imports the ''os'' package to acess its "Stdout" variable, of type
|
This version imports the ''os'' package to acess its "Stdout" variable, of type
|
||||||
"*OS.FD"; given "OS.Stdout" we can use its "WriteString" method to print the string.
|
"*OS.FD". The "import" statement is a declaration: it names the identifier ("OS")
|
||||||
|
that will be used to access members of the package imported from the file ("os"),
|
||||||
|
found in the current directory or in a standard location.
|
||||||
|
Given "OS.Stdout" we can use its "WriteString" method to print the string.
|
||||||
|
|
||||||
The comment convention is the same as in C++:
|
The comment convention is the same as in C++:
|
||||||
|
|
||||||
|
|
@ -517,14 +520,64 @@ Now "main"'s interface to the prime sieve is a channel of primes:
|
||||||
|
|
||||||
--PROG progs/sieve1.go /func.main/ /^}/
|
--PROG progs/sieve1.go /func.main/ /^}/
|
||||||
|
|
||||||
Service
|
Multiplexing
|
||||||
----
|
----
|
||||||
|
|
||||||
here we will describe this server:
|
With channels, it's possible to serve multiple independent client goroutines without
|
||||||
|
writing an actual multiplexer. The trick is to send the server a channel in the message,
|
||||||
|
which it will then use to reply to the original sender.
|
||||||
|
A realistic client-server program is a lot of code, so here is a very simple substitute
|
||||||
|
to illustrate the idea. It starts by defining "Request" type, which embeds a channel
|
||||||
|
that will be used for the reply.
|
||||||
|
|
||||||
--PROG progs/server.go
|
--PROG progs/server.go /type.Request/ /^}/
|
||||||
|
|
||||||
and this modification, which exits cleanly
|
The server will be trivial: it will do simple binary operations on integers. Here's the
|
||||||
|
code that invokes the operation and responds to the request:
|
||||||
|
|
||||||
--PROG progs/server1.go /func.Server/ END
|
--PROG progs/server.go /type.BinOp/ /^}/
|
||||||
|
|
||||||
|
The "Server" routine loops forever, receiving requests and, to avoid blocking due to
|
||||||
|
a long-running operation, starting a goroutine to do the actual work.
|
||||||
|
|
||||||
|
--PROG progs/server.go /func.Server/ /^}/
|
||||||
|
|
||||||
|
We construct a server in a familiar way, starting it up and returning a channel to
|
||||||
|
connect to it:
|
||||||
|
|
||||||
|
--PROG progs/server.go /func.StartServer/ /^}/
|
||||||
|
|
||||||
|
Here's a simple test. It starts a server with an addition operator, and sends out
|
||||||
|
lots of requests but doesn't wait for the reply. Only after all the requests are sent
|
||||||
|
does it check the results.
|
||||||
|
|
||||||
|
--PROG progs/server.go /func.main/ /^}/
|
||||||
|
|
||||||
|
One annoyance with this program is that it doesn't exit cleanly; when "main" returns
|
||||||
|
there are a number of lingering goroutines blocked on communication. To solve this,
|
||||||
|
we provide a second, "quit" channel to the server:
|
||||||
|
|
||||||
|
--PROG progs/server1.go /func.StartServer/ /^}/
|
||||||
|
|
||||||
|
It passes the quit channel to the "Server" function, which uses it like this:
|
||||||
|
|
||||||
|
--PROG progs/server1.go /func.Server/ /^}/
|
||||||
|
|
||||||
|
Inside "Server", a "select" statement chooses which of the multiple communications
|
||||||
|
listed by its cases can proceed. If all are blocked, it waits until one can proceed; if
|
||||||
|
multiple can proceed, it chooses one at random. In this instance, the "select" allows
|
||||||
|
the server to honor requests until it receives a quit message, at which point it
|
||||||
|
returns, terminating its execution. (The language doesn't yet allow the ":="
|
||||||
|
syntax in "select" statements, although it might one day. Also, observe the use
|
||||||
|
of the binary, infix form of the receive operator.)
|
||||||
|
|
||||||
|
|
||||||
|
All that's left is to strobe the "quit" channel
|
||||||
|
at the end of main:
|
||||||
|
|
||||||
|
--PROG progs/server1.go /adder,.quit/
|
||||||
|
...
|
||||||
|
--PROG progs/server1.go /quit....true/
|
||||||
|
|
||||||
|
There's a lot more to Go programming and concurrent programming in general but this
|
||||||
|
quick tour should give you some of the basics.
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,13 @@
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
type BinOp (a, b int) int;
|
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
a, b int;
|
a, b int;
|
||||||
replyc *chan int;
|
replyc *chan int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BinOp (a, b int) int;
|
||||||
|
|
||||||
func Run(op *BinOp, request *Request) {
|
func Run(op *BinOp, request *Request) {
|
||||||
result := op(request.a, request.b);
|
result := op(request.a, request.b);
|
||||||
request.replyc -< result;
|
request.replyc -< result;
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,13 @@
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
type BinOp (a, b int) int;
|
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
a, b int;
|
a, b int;
|
||||||
replyc *chan int;
|
replyc *chan int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BinOp (a, b int) int;
|
||||||
|
|
||||||
func Run(op *BinOp, request *Request) {
|
func Run(op *BinOp, request *Request) {
|
||||||
result := op(request.a, request.b);
|
result := op(request.a, request.b);
|
||||||
request.replyc -< result;
|
request.replyc -< result;
|
||||||
|
|
@ -20,7 +20,7 @@ func Server(op *BinOp, service *chan *Request, quit *chan bool) {
|
||||||
for {
|
for {
|
||||||
var request *Request;
|
var request *Request;
|
||||||
select {
|
select {
|
||||||
case request <- service: // can't say request := <-service here yet
|
case request <- service:
|
||||||
go Run(op, request); // don't wait for it
|
go Run(op, request); // don't wait for it
|
||||||
case <-quit:
|
case <-quit:
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ func Generate() *chan int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter out input values divisible by 'prime', send rest to returned channel
|
// Filter out input values divisible by 'prime', send rest to returned channel
|
||||||
func Filter(in *chan int, prime int) *chan int{
|
func Filter(in *chan int, prime int) *chan int {
|
||||||
out := new(chan int);
|
out := new(chan int);
|
||||||
go func(in *chan int, out *chan int, prime int) {
|
go func(in *chan int, out *chan int, prime int) {
|
||||||
for {
|
for {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue