Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
G
golang
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
golang
Commits
6820196b
Commit
6820196b
authored
Sep 16, 2008
by
Rob Pike
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
section on service multiplexing
R=gri DELTA=75 (57 added, 4 deleted, 14 changed) OCL=15394 CL=15398
parent
1841f311
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
65 additions
and
12 deletions
+65
-12
go_tutorial.txt
doc/go_tutorial.txt
+59
-6
server.go
doc/progs/server.go
+2
-2
server1.go
doc/progs/server1.go
+3
-3
sieve1.go
doc/progs/sieve1.go
+1
-1
No files found.
doc/go_tutorial.txt
View file @
6820196b
...
...
@@ -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 ("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++:
...
...
@@ -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/server
1.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.
doc/progs/server.go
View file @
6820196b
...
...
@@ -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
;
...
...
doc/progs/server1.go
View file @
6820196b
...
...
@@ -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
;
...
...
doc/progs/sieve1.go
View file @
6820196b
...
...
@@ -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
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment