注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

snoopyxdy的博客

https://github.com/DoubleSpout

 
 
 

日志

 
 

golang并发示例(二)  

2013-09-06 15:03:29|  分类: golang |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
1、多路客户端的服务器程序

基于管道,我们可以很容易实现一个支持多路客户端的服务器程序。采用的技巧是将每个客户端私有的通信管道 作为消息的一部分发送给服务器,然后服务器通过这些管道和客户端独立通信。现实中的服务器实现都很复杂, 我们这里只给出一个服务器的简单实现来展现前面描述的技巧。首先定义一个"request"类型,里面包含一个客户端的通信管道。

type request struct { //创建一个request对象

a, b int replyc chan int }

服务器对客户端发送过来的两个整数进行运算。下面是具体的函数,函数在运算完之后将结构通过结构中的管道返回给客户端。

type binOp func(a, b int) int //定义一个binOp类型 表示函数 xxx 类型 func run(op binOp, req *request) { //将函数op 和结构体 req传入run函数

reply := op(req.a, req.b) req.replyc <- reply }

第14行现定义一个"binOp"函数类型,用于对两个整数进行运算。

服务器routine线程是一个无限循环,它接受客户端请求。然后为每个客户端启动一个独立的routine线程, 用于处理客户数据(不会被某个客户端阻塞)。

func server(op binOp, service chan *request) { for { req := <-service go run(op, req) // don't wait for it } }

启动服务器的方法也是一个类似的routine线程,然后返回服务器的请求管道。

 func startServer(op binOp) chan *request {
          req := make(chan *request)
          go server(op, req)
          return req
     }

这里是一个简单的测试。首先启动服务器,处理函数为计算两个整数的和。接着向服务器发送"N"个请求(无阻塞)。 当所有请求都发送完了之后,再进行验证返回结果。

func main() { adder := startServer(func(a, b int) int { return a + b }) const N = 100 var reqs [N]request for i := 0; i < N; i++ { req := &reqs[i] req.a = i req.b = i + N req.replyc = make(chan int) adder <- req } for i := N-1; i >= 0; i-- { // doesn't matter what order if <-reqs[i].replyc != N + 2*i { fmt.Println("fail at", i) } } fmt.Println("done") }



1、多路客户端的服务器程序(改进版)
前面的服务器程序有个小问题:当main函数退出之后,服务器没有关闭,而且可能有一些客户端被阻塞在 管道通信中。为了处理这个问题,我们可给服务器增加一个控制管道,用于退出服务器。

func startServer(op binOp) (service chan *request, quit chan bool) { service = make(chan *request) quit = make(chan bool) go server(op, service, quit) return service, quit }

首先给"server"函数增加一个控制管道参数,然后这样使用:

func server(op binOp, service chan *request, quit chan bool) { for { select { case req := <-service: go run(op, req) // don't wait for it case <-quit: return } } }

在服务器函数中,"select"操作服用于从多个通讯管道中选择一个就绪的管道。如果所有的管道都没有数据, 那么将等待知道有任意一个管道有数据。如果有多个管道就绪,则随即选择一个。服务器处理客户端请求,如果 有退出消息则退出。

最后是在main函数中保存"quit"管道,然后在退出的时候向服务线程发送停止命令。

adder, quit := startServer(func(a, b int) int { return a + b }) ... quit <- true

当然,Go语言及并行编程要讨论的问题很多。这个入门只是给出一些简单的例子。

  评论这张
 
阅读(1529)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016