]> Cypherpunks repositories - gostls13.git/commitdiff
section on service multiplexing
authorRob Pike <r@golang.org>
Tue, 16 Sep 2008 20:14:44 +0000 (13:14 -0700)
committerRob Pike <r@golang.org>
Tue, 16 Sep 2008 20:14:44 +0000 (13:14 -0700)
R=gri
DELTA=75  (57 added, 4 deleted, 14 changed)
OCL=15394
CL=15398

doc/go_tutorial.txt
doc/progs/server.go
doc/progs/server1.go
doc/progs/sieve1.go

index f9f28d217599a1d5f0ee9add839d883b605fc1d8..fb6717ed0a22a3acf688cbb39626d8fc1a2c250a 100644 (file)
@@ -51,7 +51,10 @@ program that doesn't depend on "print()":
 --PROG progs/helloworld2.go
 
 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 (&quot;os&quot;),
+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++:
 
@@ -517,14 +520,64 @@ Now "main"'s interface to the prime sieve is a channel of primes:
 
 --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.
index 3f64e9df009bbef0ade730a63feac64dc7a937d3..00bc3b96d5fda1d3492d9135387940d60568aa06 100644 (file)
@@ -4,13 +4,13 @@
 
 package main
 
-type BinOp (a, b int) int;
-
 type Request struct {
        a, b    int;
        replyc  *chan int;
 }
 
+type BinOp (a, b int) int;
+
 func Run(op *BinOp, request *Request) {
        result := op(request.a, request.b);
        request.replyc -< result;
index 5d24d8a4affb9f4891d6e54a533e4773e1176f2e..9f6c709b389f6fcb34a109cc7c3e400fac50e9ff 100644 (file)
@@ -4,13 +4,13 @@
 
 package main
 
-type BinOp (a, b int) int;
-
 type Request struct {
        a, b    int;
        replyc  *chan int;
 }
 
+type BinOp (a, b int) int;
+
 func Run(op *BinOp, request *Request) {
        result := op(request.a, request.b);
        request.replyc -< result;
@@ -20,7 +20,7 @@ func Server(op *BinOp, service *chan *Request, quit *chan bool) {
        for {
                var request *Request;
                select {
-               case request <- service:      // can't say request := <-service here yet
+               case request <- service:
                        go Run(op, request);  // don't wait for it
                case <-quit:
                        return;
index 2cb90600b87b74b53c66e7646fa809b99e442489..2d6e069f40a8089913e340f4a0c2ebd1b97ec1e6 100644 (file)
@@ -16,7 +16,7 @@ func Generate() *chan int {
 }
 
 // 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);
        go func(in *chan int, out *chan int, prime int) {
                for {