当前位置: 首页 > news >正文

网站建设证有上海网站被查

网站建设证有,上海网站被查,必应收录提交入口,水果网站建设案例一、单元测试 Go自带一个轻量级的测试框架testing和自带的go test命令来实现单元测试和性能测试。 1.确保每个函数时可运行#xff0c;并且运行结果是正确的。 2.确保写出来的代码性能是好的。 3.单元测试能及时的发现程序设计或实现的逻辑错误#…一、单元测试 Go自带一个轻量级的测试框架testing和自带的go test命令来实现单元测试和性能测试。 1.确保每个函数时可运行并且运行结果是正确的。 2.确保写出来的代码性能是好的。 3.单元测试能及时的发现程序设计或实现的逻辑错误使问题及早暴露便于问题的定位解决。而性能测试的重点在于发现程序设计上的一些问题让程序能够在高并发的情况下还能保持稳定。 运用测试用例的指令 go test运行正确时无日志运行错误时会输出日志。 go test -v运行正确或者错误都会输出日志。 1.1、单元测试的快速入门判断一个函数的执行结果是否符合预期 1.测试用例文件必须以_test.go结尾文件不能命名为_test.gotest.gotest_xxx.go 2.测试用例文件内任何 Test开头且首字母大写的函数(例:TestXxx)都会被执行文件内不需要写main函数 3.TestXxx(t *testing.T)的形参类型必须时*testing.T 4.出现错误时可以使用t.Fatalf来格式化错误信息并退出程序 5.t.Logf方法可以输出相应的日志 6.测试用例函数没有main函数也正常执行了这也是测试用例的方便之处 7.PASS表示测试用例运行成功FAIL表示测试用例运行失败 8.测试单个文件cal_test.go一定要带上被测试的原文件go test -v cal_test.go main.go 9.测试单个方法go test -v -test.run(固定参数) TestAddUpper(函数名) package mainimport (fmttesting )// 使用go test命令能够自动执行如下形式的任何函数 // func TestXxx(*testing.T)其中Xxx可以是任何字母或字符串(第一个字母不能是[a-z]) func TestAddUpper(t *testing.T) {res : AddUpper(10)if res ! 55 {t.Fatalf(AddUpper函数执行错误,期望值:%v 返回值:%v,55,res)}t.Logf(AddUpper函数执行成功) }func TestSudada(t *testing.T) {fmt.Println(函数TestSudada被执行) }测试函数xxx.go文件内包含要测试的函数文件内不需要写main函数。 package main// xxx_test.go 内调用的函数 func AddUpper(n int) int {res:0for i:0;i10;i{resi}return res } go test命令执行错误时的返回结果 go test命令执行正确时的返回 1.2、单元测试-综合案例 测试用例文件store_test.go测试结构体的序列化和反序列化 package mainimport (fmttesting )// 测试用例TestStore func TestStore(t *testing.T) {// 先创建结构体变量var monster Monster{Name: 牛魔王,Age: 18,Skill: 蛮牛冲撞,}StoreRes:monster.Store()if !StoreRes {fmt.Println(Store函数测试错误返回值不为ture)}// 返回值// RUN TestStore// Store方法执行成功test.txt文件保存成功// --- PASS: TestStore (0.00s) }// 测试用例TestReStore func TestReStore(t *testing.T) {// 先创建结构体变量var monster Monster{}ReStoreRes:monster.ReStore()if !ReStoreRes {fmt.Println(ReStore函数测试错误返回值不为ture)}// 返回值// RUN TestReStore// ReStore方法执行成功反序列化的值为 {牛魔王 18 蛮牛冲撞}// --- PASS: TestReStore (0.00s) } 被测试对象main.go结构体和方法 package mainimport (encoding/jsonfmtio/ioutil )type Monster struct {Name stringAge intSkill string }func (this *Monster)Store() bool {// 序列化结构体变量data, err : json.Marshal(this)if err ! nil {fmt.Println(序列化失败,err)return false}// 把序列化后的数据写入到test.txt文件内WriteFileErr :ioutil.WriteFile(test.txt,data,0666)if WriteFileErr ! nil{fmt.Println(文件保存失败,WriteFileErr)return false}fmt.Println(Store方法执行成功test.txt文件保存成功)return true }func (this *Monster)ReStore() bool {// 从文件中读取序列化的数据data, ReadFileErr : ioutil.ReadFile(test.txt)if ReadFileErr ! nil{fmt.Println(文件读取失败,ReadFileErr)return false}// 将读到的数据执行反序列化err : json.Unmarshal(data, this)if err ! nil{fmt.Println(反序列化失败,err)return false}fmt.Println(ReStore方法执行成功反序列化的值为,this)return true }二、goroutine协程 一个go线程上可以起多个协程协程是轻量级的线程。 Go协程的特点有独立的栈空间共享程序堆空间调度由用户控制协程是轻量级的线程 2.1、gorouting快速入门案例 协程的执行流程 1.程序开始进程/主线程开始执行 2.go test() 开启协程协程此时开始执行如果主线程退出了那么无论协程是否执行完毕都会退出 3.主线程(main)执行代码逻辑 4.主线程结束程序退出。 案例在主线程中启动一个gorouting该协程每隔1秒输出一个hello world package mainimport (fmttime )// func test() {for i:0;i10;i {fmt.Println(test() hello world,i)time.Sleep(time.Second)} }func main() {// 开启一个协程go test()for i:0;i10;i {fmt.Println(main() hello world,i)time.Sleep(time.Second)} }// 输出结果 main() hello world 0 test() hello world 0 test() hello world 1 main() hello world 1 main() hello world 2 test() hello world 2 test() hello world 3 main() hello world 3 main() hello world 4 test() hello world 4 test() hello world 5 main() hello world 5 main() hello world 6 test() hello world 6 test() hello world 7 main() hello world 7 main() hello world 8 test() hello world 8 test() hello world 9 main() hello world 9 2.1.1、协程的快速入门小结 1.主线程是物理线程作用在CPU上。是重量级的非常耗费cpu资源。 2.协程是从主线程开启的是轻量级的线程是逻辑态对资源消耗相对小。 3.Golang的协程机制是重要的特点可以轻松开启上万个协程。 2.2、MPG模式 M操作系统的主线程 P协程执行需要的上下文 G协程gorouting 2.3、Go设置运行cpu数目 为了充分利用多CPU的优势在golang程序中设置运行的cpu数目go1.8版本之后默认让程序运行在多核上可不设置 package mainimport (fmtruntime )func main() {// 常看当前主机的CPU核数cpuNum:runtime.NumCPU()fmt.Println(cpuNum)// 可以自定义设置golang运行的cpu数runtime.GOMAXPROCS(5)fmt.Println(ok) } 三、channel管道 在运行程序时如何知道是否存在资源争抢的问题 在编译程序时增加一个参数 -race 即可。 3.1、全局锁的定义和使用 // 定义一个全局互斥锁 var lock sync.Mutexfunc main() {// 加锁lock.Lock()代码逻辑...// 解锁lock.Unlock() } 3.2、channel(管道)的基本介绍 - 引用类型 3.2.1、为什么要使用channel 1.channel本质就是一个数据结构-队列 (先进先出) 2.线程安全多gorouting访问时不需要加锁就是说channel本身就是线程安全的 (多个协程操作同一个管道时不会发生资源竞争问题) 3.channel是有类型的一个string类型的channel只能存放string类型数据 3.2.2、channel的基本语法 var 变量名 chan 数据类型 var intChan chan int intChan用于存放int数据 var mapChan chan map[int]string mapChan用于存放map[int]string数据 var perChan chan Person perChan用于存放结构体 var perChan chan *Person perChan用于存放结构体指针 说明 channel是引用类型 channel必须初始化才能雪茹数据即make后才能使用 3.3、channel的快速入门管道创建写数据读数据 package mainimport fmtfunc main() {// 定义intChanvar intChan chan int// 初始化intChan初始化类型为chan类型为int容量为3intChan make(chan int, 3)// 查看管道的值是什么fmt.Println(intChan) // 得到的是一个指针地址// 向管道中写入数据写入的数据数量不能超过管道的容量如果超过会报错deadlockintChan- 10 // - 10 向管道内写入一个数据10num:20intChan-num // - num 向管道内写入一个变量的值20// 查看管道的长度追加了2个数据fmt.Println(len(intChan)) // 返回值2// 查看管道的cap(容量)make时设置的容量为3fmt.Println(cap(intChan)) // 返回值3// 从管道中取出一个值长度会减少容量不变var num2 intnum2 -intChanfmt.Println(num2) // 返回值为10//var num3 int//num3 -intChan//fmt.Println(num3) // 返回值为20// 取出一个数据不接收-intChan// 管道的数据全部取完后会报错deadlockvar num4 intnum4 -intChanfmt.Println(num4) // 返回值为deadlock! }3.3.1、channel的注意事项 1.channel定义好了数据类型之后只能存放指定的数据类型 2.channel的数据存满之后就不能在存入了 3.channel的数据取完之后才可以继续存入 4.在没有使用协程的情况下如果channel的数据取完了再取的话就会报错deadlock。 3.3.2、案例1创建一个intChan存放int类型的数据然后取出 package mainimport fmtfunc main() {// 定义intChanvar intChan chan int// 初始化chanintChan make(chan int, 10)// 给管道添加值intChan-10intChan-20intChan-30// 从管道取值num1:-intChannum2:-intChannum3:-intChanfmt.Println(num1,num2,num3) } 3.3.3、案例2创建一个mapChan存放map[string]string数据然后取出 package mainimport fmtfunc main() {// 定义chanvar mapChan chan map[string]string// 初始化chanmapChan make(chan map[string]string,10)// 给管道添加值map类型先makem1 : make(map[string]string,10)m1[name1]北京m1[name2]天津m2 : make(map[string]string,10)m2[name1]上海m2[name2]南京mapChan-m1mapChan-m2// 从管道取值m11:-mapChanm22:-mapChanfmt.Println(m11) // map[name1:北京 name2:天津]fmt.Println(m22) // map[name1:上海 name2:南京] } 3.3.4、案例3创建一个catChan存放Cat结构体变量数据然后取出 package mainimport fmttype Cat struct {Name stringAge int }func main() {// 定义chanvar catChan chan Cat// 初始化chancatChan make(chan Cat,10)cat1:Cat{Name: Tom,Age: 2,}cat2:Cat{Name: TTome,Age: 2,}// 给管道赋值catChan-cat1catChan-cat2// 管道取值cat11:-catChancat22:-catChanfmt.Println(cat11) // 返回值{Tom 2}fmt.Println(cat22) // 返回值{TTome 2} } 3.3.5、案例4创建一个allChan存放任意类型的数据然后取出 package mainimport fmttype Cat struct {Name stringAge int }func main() {// 定义chanallChan : make(chan any,3)// chan赋值allChan-sudadaallChan-123cat:Cat{Name: Tom,Age: 2,}allChan-cat// 只想获取管道的第三个值时需要现将前2个值推出-allChan-allChan// 获取到的第三个值cat1:-allChanfmt.Println(cat1) // 返回值{Tom 2}// 查看管道内值的类型fmt.Printf(%T\n,cat1) // 返回值main.Cat// fmt.Println(cat1.Name) // 直接获取结构体的值会报错cat1.Name undefined (type any has no field or method Name)// 使用类型断言newCat:cat1.(Cat)fmt.Println(newCat.Name) // 返回值Tom } 3.4、channel的遍历和关闭 3.4.1、channel的关闭 close(xxxChan) 使用内置函数close()就可以关闭channel当channel关闭后就不能在往里面写数据了但是仍然可以读取数据。 package mainimport fmtfunc main() {// 定义并初始化chanintChan:make(chan int,3)// 管道赋值intChan-100intChan-200// 管道关闭close(intChan)//intChan-300 // 管道关闭后在往里面写数据时会报错panic: send on closed channel// 管道关闭后读取值num1:-intChannum2:-intChanfmt.Println(num1) // 返回值100fmt.Println(num2) // 返回值200 } 3.4.2、channel的遍历for -- range 1.在遍历时如果channel没有关闭则会出现deadlock的错误。 2.在遍历时如果channel已经关闭则会正常遍历数据遍历完毕后退出。 package mainimport fmtfunc main() {// 定义并初始化chanintChan:make(chan int,100)// 管道赋值for i:1;i100;i{intChan-i}// 关闭管道如果不关闭会报错deadlockclose(intChan)// for-range遍历管道for v: range intChan {fmt.Println(v) // 返回值1...100} } 3.5、gorouting和chnnel结合使用的案例 1.开启一个writeData协程向管道intChan写入10个整数 2.开启一个readData协程从管道intChan内读取10个整数 3.writeData和readData操作的是同一个管道 4.主线程需要等待writeData和readData协程都完成工作才退出 流程图解 代码实现 package mainimport (fmttime )func writeData(intChan chan int) {for i:0;i10;i{// 写之前等1秒模拟一边写一边读的场景time.Sleep(time.Second)// 管道内放入数据intChan-ifmt.Println(writeData: ,i)}// 关闭管道不在写数据之后就把管道关闭但还可以继续读管道的数据close(intChan) }func readData(intChan chan int, exitChan chan bool) {for {// 读之前等1秒模拟一边写一边读的场景time.Sleep(time.Second)// 管道内取值并判断是否取值成功v, ok : -intChanif !ok {break}fmt.Println(readData: ,v)}// intChan管道内的所有值全部都取出后往exitChan写一个数据并关闭管道exitChan-trueclose(exitChan) }func main() {// 创建2个管道intChan : make(chan int,10)exitChan : make(chan bool,1)// 调用协程go writeData(intChan)go readData(intChan,exitChan)// 主进程读取exitChan管道内的数据取到值之后再退出否则就一直等待for {// 管道内取值并判断是否取值成功_, ok : -exitChanif ok {break}} }// 返回值 //writeData: 0 //readData: 0 //writeData: 1 //readData: 1 //writeData: 2 //readData: 2 //writeData: 3 //readData: 3 //writeData: 4 //readData: 4 //writeData: 5 //readData: 5 //writeData: 6 //readData: 6 //writeData: 7 //readData: 7 //writeData: 8 //readData: 8 //writeData: 9 //readData: 9 3.6、阻塞 编译器在运行时发现一个管道只有写而没有读就会阻塞。如果有(缓慢的)读取管道内的数据时就不会阻塞 举例管道的容量为10但是放入管道的数据量超过了10或者一直没有取出管道内的数据就会阻塞报错deadlock 案例1一直往管道内写数据当写入的数据量超过管道的容量时就会阻塞报错deadlock package mainimport (fmt )func writeData(intChan chan int) {for i:0;i10;i{// 写之前等1秒模拟一边写一边读的场景//time.Sleep(time.Second)// 管道内放入数据intChan-ifmt.Println(writeData: ,i)}// 关闭管道不在写数据之后就把管道关闭但还可以继续读管道的数据close(intChan) }func readData(intChan chan int, exitChan chan bool) {for {// 读之前等1秒模拟一边写一边读的场景//time.Sleep(time.Second)// 管道内取值并判断是否取值成功v, ok : -intChanif !ok {break}fmt.Println(readData: ,v)}// intChan管道内的所有值全部都取出后往exitChan写一个数据并关闭管道exitChan-trueclose(exitChan) }func main() {// 创建2个管道intChan : make(chan int,5)exitChan : make(chan bool,1)// 调用协程go writeData(intChan)//go readData(intChan,exitChan)// 主进程读取exitChan管道内的数据取到值之后再退出否则就一直等待for {// 管道内取值并判断是否取值成功_, ok : -exitChanif ok {break}} }// 返回值 fatal error: all goroutines are asleep - deadlock! 案例2在往管道内写数据时如果如果有协程在(缓慢的)去读/取(消费)管道内的数据那么就不会阻塞 package mainimport (fmttime )func writeData(intChan chan int) {for i:0;i10;i{// 写之前等1秒模拟一边写一边读的场景//time.Sleep(time.Second)// 管道内放入数据intChan-ifmt.Println(writeData: ,i)}// 关闭管道不在写数据之后就把管道关闭但还可以继续读管道的数据close(intChan) }func readData(intChan chan int, exitChan chan bool) {for {// 读之前等1秒模拟一边写一边读的场景time.Sleep(time.Second)// 管道内取值并判断是否取值成功v, ok : -intChanif !ok {break}fmt.Println(readData: ,v)}// intChan管道内的所有值全部都取出后往exitChan写一个数据并关闭管道exitChan-trueclose(exitChan) }func main() {// 创建2个管道intChan : make(chan int,5)exitChan : make(chan bool,1)// 调用协程go writeData(intChan)go readData(intChan,exitChan)// 主进程读取exitChan管道内的数据取到值之后再退出否则就一直等待for {// 管道内取值并判断是否取值成功_, ok : -exitChanif ok {break}} }// 返回值 writeData: 0 writeData: 1 writeData: 2 writeData: 3 writeData: 4 readData: 0 writeData: 5 readData: 1 writeData: 6 writeData: 7 readData: 2 readData: 3 writeData: 8 readData: 4 writeData: 9 readData: 5 readData: 6 readData: 7 readData: 8 readData: 93.7、协程求素数的实现 统计1-1000个数字中哪些是素数 package mainimport (fmt )// 往管道内放入1000个数 func putNum(intChan chan int) {for i : 0; i 100; i {intChan - i}// 关闭intChanclose(intChan) }// 从管道intChan内取数据判断是否为素数把素数放入primeChan。取完后往exitChan写入一个true func putPrimeNum(intChan chan int, primeChan chan int, exitChan chan bool) {var flag boolfor {// 从管道intChan内取数据num,ok:-intChan// 管道intChan内的数据取完就退出if !ok {break}// 假设是素数flag true// 判断是否为素数for i:2;inum;i{if num %i 0 { // 为0说明不是素数flag falsebreak}}if flag {// 把素数放入管道primeChanprimeChan-num}}// 向退出的管道exitChan写入一个true即可fmt.Println(协程putPrimeNum取不到数据退出)exitChan-true }func main() {// 存放整数的chanvar intChan chan intintChan make(chan int, 100)// 存放素数的chanvar primeChan chan intprimeChan make(chan int, 200)// 标识退出的chanvar exitChan chan boolexitChan make(chan bool, 4)// 开启协程向intChan放入1000个数go putNum(intChan)// 开启协程从intChan里面取数据并判断是否为素数如果是就放入primeChanfor i:0;i4;i{go putPrimeNum(intChan,primeChan,exitChan)}// 退出主线程之前先判断exitChan管道内的值是否都会truego func(){for i:0;i4;i{-exitChan}// 如果从exitChan管道内取出了4个true就可以退出主线程了close(primeChan)}()// 遍历primeChan把值取出for{num,ok:-primeChanif !ok {break}fmt.Println(素数: ,num)}fmt.Println(主线程退出)// 返回值// 素数: 。。。// 协程putPrimeNum取不到数据退出// 协程putPrimeNum取不到数据退出// 协程putPrimeNum取不到数据退出// 协程putPrimeNum取不到数据退出// 主线程退出 }3.8、channel的使用细节和注意事项 1.channel可以定义为只读或者只写模式应用场景把一个可读可写的管道传入一个函数函数内对管道做下封装只允许读/写 只读模式只写模式的代码定义 package mainimport fmtfunc main() {// 定义一个只写的管道var intChanWrite chan- intintChanWrite make(chan- int,3)intChanWrite-10// 只写的管道的不能取数据// num:-intChan// 定义一个只读的管道var intChanRead -chan intintChanRead make(-chan int,3)num:-intChanReadfmt.Println(num) // 因为管道内没有数据这里取不到值// 只读的管道的不能写数据//intChanRead-10 } 2.使用select可以解决从管道内取数据阻塞的问题 package mainimport (fmt )func main() {// 定义管道并存放值intChan : make(chan int,10)for i:0;i10;i{intChan-i}stringChan : make(chan string,5)for i:0;i5;i{stringChan-hellofmt.Sprintf(%d,i)}// 传统的方式在遍历管道时如果不关闭管道会deadlock阻塞// 实际开发中不好确认什么时候关闭管道此时使用select解决从管道内取数据时阻塞的问题for {select {// 如果管道intChan没有关闭同时又取不到值时不会deadlock阻塞会去下一个case取值case v: -intChan:fmt.Println(从intChan管道内取到的值,v)// 如果管道stringChan没有关闭同时又取不到值时不会deadlock阻塞会去下一个case取值case v: -stringChan:fmt.Println(从stringChan管道内取到的值,v)// 默认逻辑default:fmt.Println(管道内取不到值了。。。)return}} } 3.协程中使用recover解决协程中出现panic导致程序崩溃的问题 package mainimport (fmttime )func test() {// defer recover 捕获当前函数抛出的panic错误defer func() {err:recover()if err ! nil {fmt.Println(test函数发生错误,err)}}()// 函数的代码逻辑这里故意写的错误代码触发报错var testmap map[int]stringtestmap[0]sudada }func main() {go test()// 正常的代码执行不加recover时协程报错整个程序就退出了。加上recover后协程报错了不影响正常代码的执行for {fmt.Println(main)time.Sleep(time.Second)}// 返回值// main// test函数发生错误 assignment to entry in nil map// main }
http://www.zqtcl.cn/news/942222/

相关文章:

  • 阳江房地产信息网官方网站创业网站开发要多少钱
  • 工业设计招聘信息网站常用的seo网站优化排名
  • 温岭市建设规划局网站网站规划与建设ppt
  • 龙岩网站建设较好的公司做网站销售的换工作
  • 潞城建设局网站建设网站服务器自营方式的特点
  • 西安网站seo公司东莞市专注网站建设怎么样
  • dede游戏网站模板如何做盆栽蔬菜网站
  • 江都建设网站网站开发技术介绍
  • 网站介绍视频怎么做网站建设优化服务
  • 可以左右滑动的网站有口碑的盐城网站建设
  • 360报危险网站注册界面设计
  • 不用淘宝客api如何做网站北京移动官网网站建设
  • 手表哪个网站做的好河北网站备案流程
  • 凡科做的网站推效果网站做seo第一步
  • 建设在线观看视频网站免费企业网站建设免费
  • 网站开发需要后台吗哪家建站公司好
  • 个人建设网站论文网站视频怎么做的
  • 不同类型的购物网站汉川网站建设
  • 网站开发需求文档范文广州公司网站托管
  • 网站制作公司官网首页撸撸撸做最好的导航网站
  • 网站建设毕业设计综述centos 安装wordpress lnmp
  • 济宁专业做网站网站建设中 html
  • 中国排名高的购物网站最新发布的手机2022
  • 备案的网站名与公司名称出国用哪个地图app好
  • 网站建设工作室图片文章资讯类网站
  • 深圳自助建站系统网站题目有哪些
  • 郑州做网站kuihuakeji软文发布的平台与板块
  • 一那个网站可以做一建题安全文化企业示范企业评价标准
  • 网站没有关键词收录phpstudy配置网站
  • 返利网站怎么做的做网站推广见客户的话术