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\n",<-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]\n", 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\n", 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:]

}

 

你可能感兴趣的:(go语言)