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:]
}
时间: 2024-08-26 16:36:33

Go语言小试牛刀---几个简单的例子的相关文章

[Graphviz]一些简单的例子(未完待续)

本文参考:http://wenku.baidu.com/link?url=kTPIn5tBY4eboEPZeOZyLwHAq-fSMoTbagsqcG5-IcpL325tnnh3ES8aky-PBjP99KpnH_DYgE41i2KZp3EuUAQbDj0Pk55kCNiF9ZcSH6K 1.设置点和线的形状和颜色 简单的例子 digraph是有向图,graph是无向图.->用在有向图中,—用在无向图中,不能混用. digraph G { //给出了图的类型和名字 main -> parse

C语言排序算法之简单交换法排序,直接选择排序,冒泡排序

C语言排序算法之简单交换法排序,直接选择排序,冒泡排序,最近考试要用到,网上也有很多例子,我觉得还是自己写的看得懂一些. 简单交换法排序 1 /*简单交换法排序 2 根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置 3 交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动 4 不稳定 5 */ 6 #include<windows.h> 7 #include<stdio.h> 8 void main(){ 9 int i,j,arr[10

用最简单的例子理解对象为Null模式(Null Object Pattern)

所谓的"对象为Null模式",就是要求开发者考虑对象为Null的情况,并设计出在这种情况下的应对方法. 拿"用最简单的例子理解策略模式(Strategy Pattern) "中的例子来说,在我们的客户端程序中只考虑了用户输入1,2,3的情况,如果用户输入其它数字,比如4,就没有一个对应的IBall接口实现类实例产生,于是会报如下的错: 为了应对这种情况,我们专门设计一个类,当用户输入1,2,3以上的数字,就产生该类的实例.该类同样实现IBall接口. public

Java 多线程编程两个简单的例子

/** * @author gao */ package gao.org; public class RunnableDemo implements Runnable{ @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<10;i++){ System.out.println("新线程输出:"+i); } } public static void main(String []

C#调用存储过程简单完整例子

CREATE PROC P_TEST@Name VARCHAR(20),@Rowcount INT OUTPUTASBEGIN SELECT * FROM T_Customer WHERE [email protected] SET  @[email protected]@ROWCOUNTENDGO------------------------------------------------------------------------------------------存储过程调用如下:-

javaweb简单登陆例子

JSP+Servlet+JavaBean简单程序例子——用户名密码登陆,摘自<Tomcat&JavaWeb 技术手册>,亲测可用. IDE环境:MyEclipse10 1.建立Web Project,命名为Login_test.创建userLogn表: create table userLogin( user_name varchar(10) not null, user_pwd varchar(10) not null, constraint user_pk primary key

命名管道-简单的例子

#include "stdafx.h" #include<iostream> #include<windows.h> #include<ctime> using namespace std; DWORD WINAPI thread1(LPVOID param) { char buf[256]; DWORD rlen=0; HANDLE hPipe = CreateNamedPipe(TEXT("\\\\.\\Pipe\\mypipe&quo

Android中关于JNI 的学习(零)简单的例子,简单地入门

Android中JNI的作用,就是让Java能够去调用由C/C++实现的代码,为了实现这个功能,需要用到Anrdoid提供的NDK工具包,在这里不讲如何配置了,好麻烦,配置了好久... 本质上,Java去调用C/C++的代码其实就是去调用C/C++提供的方法,所以,第一步,我们要创建一个类,并且定义一个Native方法,如下: JniTest类: public class JniTest { public native String getTestString(); } 可以看到,在这个方法的前

php实现socket简单的例子

一.Socket简介 1.socket只不过是一种数据结构 2.使用这个socket数据结构去开始一个客户端和服务器之间的会话 3.服务器是一直在监听准备产生一个新的会话.当一个客户端连接服务端,它就打开服务器正在进行监听的一个端口进行会话 4.服务器端接受客户端的链接请求,那么就进行一次循环.现在这个客户端就能够发送信息到服务器,服务器也能发送信息给客户端.[重点]   虽然如此,游戏服务端依旧不用php,而是用lua或c++,因为php有瓶颈,且很快到达瓶颈. 二.Socket变量 产生一个