zoukankan      html  css  js  c++  java
  • Go语言小试牛刀---几个简单的例子

    整理资料,发现之前手写的Go语言资料,现在贴过来。

    第一个:Channel的使用,创建一个随机数

    package main 
    
    import "fmt"
    import  "runtime"
    
    func rand_generator_2() chan int{
    	out := make(chan int)
    	go func(){
    		for{
    			out<-rand.Int()
    		}
    	}()
    	return out
    }
    
    func main(){
    	rand_service_handler := rand_generator_2()
    	fmt.Printf("%d
    ",<-rand_service_handler)
    }
    

    第二个:实现通过Channel通道求和的例子

    package main
    
    type NodeInterface interface {
      receive(i int)
      run() int
    }
    
    type Node struct {
      name string
      in_degree int
      in_ch chan int
      out_ch chan int
    
      inode NodeInterface
    }
    
    func NewNode(name string, inode NodeInterface) *Node {
      //创建一个Node,拥有两个channel
      return &Node{name, 0, make(chan int), make(chan int), inode}
    }
    
    func (from *Node) ConnectTo(to *Node) {
      to.in_degree++
      go func() {
        i := <- from.out_ch
        to.in_ch <- i
      }()
    }
    
    func (n *Node) Run() {
      go func() {
        defer func() {
          if x := recover(); x != nil {
            println(n.name, "panic with value ", x)
            panic(x)
          }
          println(n.name, "finished");
        }()
    
        for n.in_degree > 0 {
          received := <- n.in_ch
          n.inode.receive(received)
          n.in_degree--
        }
        ret := n.inode.run()
        n.out_ch <- ret
      }()
    }
    
    type DoubleNode struct {
      data int
    }
    //创建一个新的Node
    func NewDoubleNode(name string, data int) *Node {
      return NewNode(name, &DoubleNode{data})
    }
    
    func (n *DoubleNode) receive(i int) {
    }
    
    func (n *DoubleNode) run() int {
      return n.data * 2
    }
    
    type SumNode struct {
      data int
    }
    
    func NewSumNode(name string) *Node {
      return NewNode(name, &SumNode{0})
    }
    
    func (n *SumNode) receive(i int) {
      n.data += i
    }
    
    func (n *SumNode) run() int {
      return n.data
    }
    
    func main() {
      sum := NewSumNode("sum")
      sum.Run()
    
      for _, num := range [5]int{1, 2, 3, 5, 6} {
        node := NewDoubleNode("double", num)
        node.ConnectTo(sum)
        node.Run()
      }
    
      println(<- sum.out_ch)
    }
    

     第三个例子:Go语言的并发操作,go语言可以适配机器的cpu达到最大并发

    package main
    
    import (
    	"fmt"
    	"runtime"
    )
    
    var workers = runtime.NumCPU()
    
    type Result struct {
    	jobname    string
    	resultcode int
    	resultinfo string
    }
    
    type Job struct {
    	jobname string
    	results chan<- Result
    }
    
    func main() {
    
    	// go语言里大多数并发程序的开始处都有这一行代码, 但这行代码最终将会是多余的,
    	// 因为go语言的运行时系统会变得足够聪明以自动适配它所运行的机器
    	runtime.GOMAXPROCS(runtime.NumCPU())
    
    	// 返回当前处理器的数量
    	fmt.Println(runtime.GOMAXPROCS(0))
    	// 返回当前机器的逻辑处理器或者核心的数量
    	fmt.Println(runtime.NumCPU())
    
    	// 模拟8个工作任务
    	jobnames := []string{"gerry", "wcdj", "golang", "C++", "Lua", "perl", "python", "C"}
    	doRequest(jobnames)
    }
    
    func doRequest(jobnames []string) {
    
    	// 定义需要的channels切片
    	jobs := make(chan Job, workers)
    	results := make(chan Result, len(jobnames))
    	done := make(chan struct{}, workers)
    
    	// ---------------------------------------------
    	/*
    	 * 下面是go协程并发处理的一个经典框架
    	 */
    
    	// 将需要并发处理的任务添加到jobs的channel中
    	go addJobs(jobs, jobnames, results) // Executes in its own goroutine
    
    	// 根据cpu的数量启动对应个数的goroutines从jobs争夺任务进行处理
    	for i := 0; i < workers; i++ {
    		go doJobs(done, jobs) // Each executes in its own goroutine
    	}
    
    	// 新创建一个接受结果的routine, 等待所有worker routiines的完成结果, 并将结果通知主routine
    	go awaitCompletion(done, results)
    
    	// 在主routine输出结果
    	processResults(results)
    	// ---------------------------------------------
    
    }
    
    func addJobs(jobs chan<- Job, jobnames []string, results chan<- Result) {
    	for _, jobname := range jobnames {
    
    		// 在channel中添加任务
    		jobs <- Job{jobname, results}
    	}
    	close(jobs)
    }
    
    func doJobs(done chan<- struct{}, jobs <-chan Job) {
    
    	// 在channel中取出任务并计算
    	for job := range jobs {
    
    		/*
    		 * 定义类型自己的方法来处理业务逻辑, 实现框架和业务分离
    		 */
    		job.Do()
    	}
    
    	// 所有任务完成后的结束标志, 一个空结构体切片
    	done <- struct{}{}
    }
    
    // 方法是作用在自定义类型的值上的一类特殊函数
    func (job Job) Do() {
    
    	// 打印当前处理的任务名称
    	fmt.Printf("... doing work in [%s]
    ", job.jobname)
    
    	// 模拟处理结果
    	if job.jobname == "golang" {
    		job.results <- Result{job.jobname, 0, "OK"}
    	} else {
    		job.results <- Result{job.jobname, -1, "Error"}
    	}
    }
    
    func awaitCompletion(done <-chan struct{}, results chan Result) {
    	for i := 0; i < workers; i++ {
    		<-done
    	}
    	close(results)
    }
    
    func processResults(results <-chan Result) {
    	for result := range results {
    		fmt.Printf("done: %s,%d,%s
    ", result.jobname, result.resultcode, result.resultinfo)
    	}
    }
    

     第四个:网络编程方面,基于Go实现Ping的操作,比较难,还未看明白

    // Copyright 2009 The Go Authors.  All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    // taken from http://golang.org/src/pkg/net/ipraw_test.go
    
    package ping
    
    import (
    	"bytes"
    	"errors"
    	"net"
    	"os"
    	"time"
    )
    
    const (
    	icmpv4EchoRequest = 8
    	icmpv4EchoReply   = 0
    	icmpv6EchoRequest = 128
    	icmpv6EchoReply   = 129
    )
    
    type icmpMessage struct {
    	Type     int             // type
    	Code     int             // code
    	Checksum int             // checksum
    	Body     icmpMessageBody // body
    }
    
    type icmpMessageBody interface {
    	Len() int
    	Marshal() ([]byte, error)
    }
    
    // Marshal returns the binary enconding of the ICMP echo request or
    // reply message m.
    func (m *icmpMessage) Marshal() ([]byte, error) {
    	b := []byte{byte(m.Type), byte(m.Code), 0, 0}
    	if m.Body != nil && m.Body.Len() != 0 {
    		mb, err := m.Body.Marshal()
    		if err != nil {
    			return nil, err
    		}
    		b = append(b, mb...)
    	}
    	switch m.Type {
    	case icmpv6EchoRequest, icmpv6EchoReply:
    		return b, nil
    	}
    	csumcv := len(b) - 1 // checksum coverage
    	s := uint32(0)
    	for i := 0; i < csumcv; i += 2 {
    		s += uint32(b[i+1])<<8 | uint32(b[i])
    	}
    	if csumcv&1 == 0 {
    		s += uint32(b[csumcv])
    	}
    	s = s>>16 + s&0xffff
    	s = s + s>>16
    	// Place checksum back in header; using ^= avoids the
    	// assumption the checksum bytes are zero.
    	b[2] ^= byte(^s & 0xff)
    	b[3] ^= byte(^s >> 8)
    
    	return b, nil
    }
    
    // parseICMPMessage parses b as an ICMP message.
    func parseICMPMessage(b []byte) (*icmpMessage, error) {
    	msglen := len(b)
    	if msglen < 4 {
    		return nil, errors.New("message too short")
    	}
    	m := &icmpMessage{Type: int(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
    	if msglen > 4 {
    		var err error
    		switch m.Type {
    		case icmpv4EchoRequest, icmpv4EchoReply, icmpv6EchoRequest, icmpv6EchoReply:
    			m.Body, err = parseICMPEcho(b[4:])
    			if err != nil {
    				return nil, err
    			}
    		}
    	}
    	return m, nil
    }
    
    // imcpEcho represenets an ICMP echo request or reply message body.
    type icmpEcho struct {
    	ID   int    // identifier
    	Seq  int    // sequence number
    	Data []byte // data
    }
    
    func (p *icmpEcho) Len() int {
    	if p == nil {
    		return 0
    	}
    	return 4 + len(p.Data)
    }
    
    // Marshal returns the binary enconding of the ICMP echo request or
    // reply message body p.
    func (p *icmpEcho) Marshal() ([]byte, error) {
    	b := make([]byte, 4+len(p.Data))
    	b[0], b[1] = byte(p.ID>>8), byte(p.ID&0xff)
    	b[2], b[3] = byte(p.Seq>>8), byte(p.Seq&0xff)
    	copy(b[4:], p.Data)
    	return b, nil
    }
    
    // parseICMPEcho parses b as an ICMP echo request or reply message body.
    func parseICMPEcho(b []byte) (*icmpEcho, error) {
    	bodylen := len(b)
    	p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
    	if bodylen > 4 {
    		p.Data = make([]byte, bodylen-4)
    		copy(p.Data, b[4:])
    	}
    	return p, nil
    }
    
    func Ping(address string, timeout int) (alive bool) {
    	err := Pinger(address, timeout)
    	alive = err == nil
    	return
    }
    
    func Pinger(address string, timeout int) (err error) {
    	//拨号
    	c, err := net.Dial("ip4:icmp", address)
    
    	if err != nil {
    		return
    	}
    	//?
    	c.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Second))
    	defer c.Close()
    
    	//>>
    	typ := icmpv4EchoRequest
    	xid, xseq := os.Getpid()&0xffff, 1
    	wb, err := (&icmpMessage{
    		Type: typ, Code: 0,
    		Body: &icmpEcho{
    			ID: xid, Seq: xseq,
    			Data: bytes.Repeat([]byte("Go Go Gadget Ping!!!"), 3),
    		},
    	}).Marshal()
    	if err != nil {
    		return
    	}
    	if _, err = c.Write(wb); err != nil {
    		return
    	}
    	var m *icmpMessage
    
    	rb := make([]byte, 20+len(wb))
    
    	for {
    		if _, err = c.Read(rb); err != nil {
    			return
    		}
    		rb = ipv4Payload(rb)
    		if m, err = parseICMPMessage(rb); err != nil {
    			return
    		}
    		switch m.Type {
    		case icmpv4EchoRequest, icmpv6EchoRequest:
    			continue
    		}
    		break
    	}
    	return
    }
    
    func ipv4Payload(b []byte) []byte {
    	if len(b) < 20 {
    		return b
    	}
    	hdrlen := int(b[0]&0x0f) << 2
    	return b[hdrlen:]
    }
    
  • 相关阅读:
    倍增算法2(树上倍增)
    倍增算法1
    可持久线段树
    【BZOJ】1059: [ZJOI2007]矩阵游戏(二分图匹配)
    【BZOJ】2743: [HEOI2012]采花(树状数组)
    【BZOJ】2959: 长跑(lct+缩点)(暂时弃坑)
    【学习笔记】LCT link cut tree
    【学习笔记】FFT
    【BZOJ】1001: [BeiJing2006]狼抓兔子(最小割 / 对偶图)
    【BZOJ】1007: [HNOI2008]水平可见直线(凸包)
  • 原文地址:https://www.cnblogs.com/sansan/p/4065559.html
Copyright © 2011-2022 走看看