Go语言学习笔记(3)-goroutine,Channels

go关键字基本上就是新开一个goroutine(差不多就是线程),然后执行对应的方法。
当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们叫它main goroutine。在语法上,go语句是一个普通的函数或方法调用前加上关键字go。

f()    // 普通阻塞方法
go f() // 创建一个新的goroutine然后执行该方法

Channels就是一个读取写入阻塞的队列。两个或多个goroutine通过Channels来完成协作,一般是一个goroutine读,多个goroutine写。

使用内置的make函数,我们可以创建一个channel:

ch := make(chan int) // 可以写入读写int类型的channel

一个channel有发送和接受两个主要操作,都是通信行为。一个发送语句将一个值从一个goroutine通过channel发送到另一个执行接收操作的goroutine。

ch <‐ x  //写入
x = <‐ch // 读取
<‐ch     // 读取并直接舍弃

一个基于无缓存Channels的发送操作将导致发送者goroutine阻塞,直到另一个goroutine在相同的Channels上执行接收操作(就是和阻塞队列一样的同步机制)

select语句意思也非常简单,就是从多个阻塞队列中只要有任意一个不再阻塞,select就会被执行,可以看成是switch的同步版

select {
case <‐ch1:
    // ...
case x := <‐ch2:
    // ...use x...
case ch3 <‐ y:
    // ...
default:
    // ...
}

交替打印

ch := make(chan int, 1)
for i := 0; i < 10; i++ {
    select {
    case x := <‐ch:
        fmt.Println(x) // "0" "2" "4" "6" "8"
    case ch <‐ i:
    }
}

一个简易的聊天服务器程序

package main

import (
    "net"
    "log"
    "bufio"
    "fmt"
)

//该程序一共有2n+2个线程(n为客户端数量)
//其中一个线程监听客户端连接,一个线程负责广播消息,然后每个客户端有两个线程,一个负责读取消息,一个负责写消息
func main(){
    //设置网卡为监听模式
    listener,err:=net.Listen("tcp","localhost:8000")
    //创建失败 打印错误日志
    if err!=nil {
        log.Fatal(err)
    }

    //广播消息线程
    go broadcaster()

    //死循环监听客户端连接
    for{
        conn,err:=listener.Accept()
        if err!=nil{
            log.Fatal(err)
            continue
        }


        go handleConn(conn)

    }
}

//每个客户端开启一个单独的线程进行服务
func handleConn(conn net.Conn) {
    ch:=make(chan string)
    go clientWriter(conn,ch)

    //初始信息
    who:=conn.RemoteAddr().String()
    ch<-"You are "+who
    messages<-who+" has arrived"
    entering<-ch

    //循环读取客户端的输入,然后群发
    input:=bufio.NewScanner(conn)
    for input.Scan(){
        messages<-who+":"+input.Text()
    }

    //客户端退出
    leaving<-ch
    messages<-who+" has left"

    //关闭连接
    conn.Close()

}



func clientWriter(conn net.Conn, ch<- chan string) {

    for msg:=range ch{
        fmt.Fprintln(conn,msg)
    }
}

type client chan<- string
//三个channel用来同步消息
var (
    entering=make(chan client)
    leaving=make(chan client)
    messages=make(chan string)
)

func broadcaster() {
    clients:=make(map[client]bool)
    for{
        select {
        case msg:=<-messages:
            for cli:=range clients  {
                cli<-msg
            }
        case cli:=<-entering:
            clients[cli]=true
        case cli:=<-leaving:
            delete(clients,cli)
            close(cli)
        }
    }
}




欢迎关注我的github https://github.com/luckyCatMiao

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值