go语言学习第五天==>并发编程,go关键词,并发通信channel、select关键字、缓冲机制、socket编程

go语言学习第五天==>并发编程,go关键词,并发通信channel、select关键字、缓冲机制、socket编程

- 并 发 编 程
goroutine是Go语言中的轻量级线程实现

go关键词
在一个函调用前加上go关键字,
这次调用就会在一个新的goroutine中并发执行,当函数返回则结束,如果这个函数有返回值则会被丢弃
demo
当mian函数结束时程序就退出,即终止所有goroutine

func Add(x, y int) {    
	z := x + y    fmt.Println(z)  
} 

go Add(1, 1)  //关键行

///
并发通信channel

channel 用于线程之间的通信,与普通变量的不同之处在于
向channel写入/读出数据的时候线程是阻塞的,直到操作完成
起到线程通信安全的作用,
其他语言是共享内存,channel是线程通信

声明形式:var 变量名 chan 变量类型

var ch chan int
var m map[string] chan bool

定义channel,直接使用make()即可

ch := make(chan int)

将数据写入(发送至)channel语法↓

ch <- value

从channel中读出数据语法↓

value := <-ch 


select关键字
用于处理异步IO问题

语法:↓(类似switch语句但是和switch有很大区别)

select {  
	case <-chan1:  // 如果chan1成功读到数据,则进行该case处理语句  
	case chan2 <- 1:  // 如果成功向chan2写入数据,则进行该case处理语句  
	default:  // 如果上面都没有成功,则进入default处理流程 
}

1 select后面不带判断条件,直接查看case
2 每个case语句后必须是channel的操作
3 有一个case执行成功则结束
4 从上到下执行case直到有一个成功的
5 如果case中的操作都没有成功则到default


缓冲机制:当需要持续传输大量数据时使用

创建使用make() 在第二个参数指定缓冲区大小↓
即使没有读取方,西二方也可以一直往channel里面写入
缓冲区用完之前都不会被阻塞

c := make(chan int, 1024) 

**缓冲读取:**与读取非缓冲区一致,但是也可以用range全部读取

for i := range c {     
	fmt.Println("Received:", i) 
}

//
超时机制
向channel西二数据时发现channel已满,
或者读取时发现channel是空的
如果不正确处理这些情况,有可能会锁死

处理方法用上面的select关键字
demo

// 首先,我们实现并执行一个匿名的超时等待函数 timeout := make(chan bool, 1) go func() {     
	time.Sleep(1e9) // 等待1秒钟     
	timeout <- true 
}() 
 
// 然后我们把timeout这个channel利用起来 
select {  
	case <-ch:   // 从ch中读取到数据  
	case <-timeout:   
	// 一直没有从ch中读取到数据,但从timeout中读取到了数据 
}

这样使用select机制可以避免永久等待问题↑

channel是原生类型不仅支持传递还支持类型转换
///
单向channel:即只允许读或者写
声明:

var ch1 chan int  // ch1是一个正常的channel,不是单向的 
var ch2 chan<- float64// ch2是单向channel,只用于写float64数据 
var ch3 <-chan int // ch3是单向channel,只用于读取int数据 

初始化

ch4 := make(chan int) 
//使用4初始化单向5
ch5 := <-chan int(ch4) // ch5就是一个单向的读取channel 
//使用4初始化单向6
ch6 := chan<- int(ch4) // ch6 是一个单向的写入channel 

关闭channel直接使用内置的close()函数即可

close(ch)

现在go语言默认只使用一个cpu,要想使用多个CPU可以这样
runtime.GOMAXPROCS(16)

获取CPU数量的函数
NumCPU()

/
Socket编程
以前网络编程的步骤:
(1) 建立Socket:使用socket()函数。
(2) 绑定Socket:使用bind()函数。
(3) 监听:使用listen()函数。或者连接:使用connect()函数。 (4) 接受连接:使用accept()函数。
(5) 接收:使用receive()函数。或者发送:使用send()函数。

但是go对此过程进行了抽象和封装,无论建立什么都只需要用
net.Dial()即可。

Dial()函数
原型:

func Dial(net, addr string) (Conn, error) 

net是网络协议名称
addr是IP地址或者域名,端口号以:形式追加
成功则返回连接对象,失败则返回错误

demo:
tcp:

conn, err := net.Dial("tcp", "192.168.0.10:2100") 

udp:

conn, err := net.Dial("udp", "192.168.0.12:975") 

ICMP:

conn, err := net.Dial("ip4:icmp", "www.baidu.com") 

ICMP使用协议编号

conn, err := net.Dial("ip4:1", "10.0.0.3") 

tcp demo

package main 
 
import (  "net"  "os"  "bytes"  "fmt" ) 
 
func main() {  
	if len(os.Args) != 2 {   
		fmt.Fprintf(os.Stderr, "Usage: %s host:port", os.Args[0])   os.Exit(1)  
	}  
	service := os.Args[1]    
	conn, err := net.Dial("tcp", service)  
	checkError(err) 
 
 	_, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n"))  
 	checkError(err) 
 	
 	result, err := readFully(conn)  
 	checkError(err) 
 
 	fmt.Println(string(result)) 
 
 	os.Exit(0) 
} 
 
func checkError(err error) {  
	if err != nil {   
		fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) 
		os.Exit(1) 
		} 
} 
 func readFully(conn net.Conn) ([]byte, error) {  
 	defer conn.Close() 
 
 	result := bytes.NewBuffer(nil)  var buf [512]byte  for {   
 		n, err := conn.Read(buf[0:])   
 		result.Write(buf[0:n])   
 		if err != nil {    
 			if err == io.EOF {     
 				break    
			}    
			return nil, err   
		}  
	}  
return result.Bytes(), nil }


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值