Java程序员学习golang六小时后,竟然深夜

   日期:2020-10-05     浏览:132    评论:0    
核心提示:写在前面       竟然大半夜不睡觉写博客。这个标题,是不是像一些无良卖课吸睛公众号,点开一看味同嚼蜡。       好吧,大半夜码字,因为实在激动。从下午六点多开始学习golang,花了三个小时了解变量、指针、数据类型、结构体、语法、函数以及golang的切片、管道、(go程)协程等特性,用半小时思考我该写个啥,花了一个半小时写了个小白入门爬虫,最后傻乐了半小时。文章目录写.

写在前面

       竟然大半夜不睡觉写博客。这个标题,是不是像一些无良卖课吸睛公众号,点开一看味同嚼蜡。

      好吧,大半夜码字,因为实在激动。从下午六点多开始学习golang,花了三个小时了解变量、指针、数据类型、结构体、语法、函数以及golang的切片、管道、(go程)协程等特性,用半小时思考我该写个啥,花了一个半小时写了个小白入门爬虫,最后傻乐了半小时。

文章目录

  • 写在前面
  • 前言
  • 一、Golang是什么?
    • 1.简介
  • 二、使用步骤
    • 1.下载镜像
    • 2.下载GoLang(别的也行,VSCode)
    • 3.开干
  • 三、核心特性
    • 1.goroutine协程
      • 1.1 什么是 Go 协程?
      • 1.2 goroutine和线程的比较
      • 1.3 goroutine协程实现原理
    • 2.channel
      • 2.1 什么是 channel?
      • 2.2 咋用?
  • 四、小小爬虫
    • 1.爬虫四步
    • 2.代码
    • 3.结果
  • 总结

前言

      我是写Java的,所以本文是浅尝辄止golang后一得之见,才疏学浅,希望对想了解golang的小伙伴有所帮助。

一、Golang是什么?

1.简介

官话:golang是Google开发的一种 静态强类型、编译型,并发型,并具有垃圾回收功能的编程语言。

个人看法:

  • 有很多C语言的影子,比如语法、控制流结构、基础数据类型、传参、指针等,方便上手(Java写习惯了,顺手扔出来的分号,是那么的格格不入无处安放)
  • 能访问底层操作系统,还提供了强大的网络编程和并发编程支持(channel和Goroutine是核心)

二、使用步骤

1.下载镜像

镜像地址

下载对应的版本就行

2.下载GoLang(别的也行,VSCode)

链接在此

3.开干

个人途径

  • 官方文档:文档一号,文档二号
  • 视频:视频在此

三、核心特性

1.goroutine协程

     大道至简

1.1 什么是 Go 协程?

先理解进程、线程 之间概念的区别

对于 进程、线程,都是有内核进行调度,有 CPU 时间片的概念,进行 抢占式调度(有多种调度算法)

  • 协程是用户级线程,对内核是透明的,系统并不知道有协程的存在。
  • 完全由用户自己的程序进行调度,通常只能进行协作式调度,需要协程自己主动把控制权转让出去之后,其他协程才能被执行到。

goroutine 和协程区别

  • 本质上,goroutine 就是协程。 不同的是,Golang 在 runtime、系统调用等多方面对 goroutine调度进行了封装和处理,当遇到长时间执行或者进行系统调用时,会主动把当前 goroutine 的CPU 转让出去,让其他goroutine 能被调度并执行。
  • 从语言层面原生支持协程,在函数或者方法前面加 go关键字就可创建一个协程。

1.2 goroutine和线程的比较

内存消耗 切换调度开销
每个 goroutine (协程) 默认占用内存远比 Java 、C 的线程少。goroutine:2KB 线程:8MB goroutine 远比线程小;线程:涉及模式切换(从用户态切换到内核态)、16个寄存器、PC、SP…等寄存器的刷新等。goroutine:只有三个寄存器的值修改 - PC / SP / DX.

1.3 goroutine协程实现原理

协程是基于线程的。内部实现上,维护了一组数据结构和 n 个线程,真正的执行还是线程,协程执行的代码被扔进一个待执行队列中,由这 n 个线程从队列中拉出来执行。这就解决了协程的执行问题。
暂时只了解到这里,待续

2.channel

2.1 什么是 channel?

channel是Go语言中各个并发结构体(goroutine)之前的通信机制。 通俗的讲,就是各个goroutine之间通信的”管道“,有点类似于Linux中的管道。

2.2 咋用?

1.声明channel
2.引用类型
3.单向channel


var 变量名 chan 数据类型

channel和和map类似,channel也一个对应make创建的底层数据结构的引用。

当我们复制一个channel或用于函数参数传递时,我们只是拷贝了一个channel引用,因此调用者和被调用者将引用同一个channel对象。和其它的引用类型一样,channel的零值也是nil。定义一个channel时,也需要定义发送到channel的值的类型。

// 方法一:channel的创建赋值

var ch chan int;

ch = make(chan int);

// 方法二:短写法

 ch:=make(chan int);

// 方法三:综合写法:全局写法!!!!

var ch = make(chan int);


单向chan

//定义只读的channel

read_only := make (<-chan int)

 
//定义只写的channel

write_only := make (chan<- int)

四、小小爬虫

1.爬虫四步

  1. 踩点(找目标)http://www.netbian.com/fengjing/index_2.htm
  2. 爬(拿数据)
  3. 过滤(获取想要的)
  4. 数据处理

2.代码

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	//存放图片的管道
	chanImageUrls chan string
	wg            sync.WaitGroup

	//监控协程
	chanTask chan string
)


func main() { 

	chanImageUrls = make(chan string, 1000000)
	chanTask = make(chan string, 26)

	for i := 2; i < 10; i++ { 
		wg.Add(1)
		go getImageUrls("http://www.netbian.com/fengjing/index_" + strconv.Itoa(i) + ".htm")
	}

	wg.Add(1)
	go checkOK()

	//下载
	for i := 0; i < 3; i++ { 
		wg.Add(1)
		go downloadImg()
	}
	wg.Wait()

}
//下载文件
func downLoadFile(url string, filename string) (ok bool) { 
	resp, err := http.Get(url)
	HandleError(err, "http.get.url")
	defer resp.Body.Close()
	bytes, err := ioutil.ReadAll(resp.Body)
	HandleError(err, "res.Body")
	filename = "D:/test/" + filename
	err = ioutil.WriteFile(filename, bytes, 0666)
	if err != nil { 
		return false
	} else { 
		return true
	}
}

//下载图片
func downloadImg() { 
	for url := range chanImageUrls { 
		filename := getFilenameFromUrl(url)
		ok := downLoadFile(url, filename)
		if ok { 
			fmt.Println(filename + "下载成功")
		} else { 
			fmt.Println(filename + "下载失败")
		}
	}

}

//截取名字
func getFilenameFromUrl(url string) (filename string) { 
	lastIndex := strings.LastIndex(url, "/")
	filename = url[lastIndex+1:]
	timePrefix := strconv.Itoa(int(time.Now().UnixNano()))
	filename = timePrefix + "_" + filename
	return

}

//任务统计协程
func checkOK() { 
	var count int
	for { 
		url := <-chanTask
		fmt.Println("完成爬取 " + url)
		count++
		if count == 26 { 
			close(chanImageUrls)
			break
		}
	}
	wg.Done()
}

//爬取图片链接到管道
func getImageUrls(url string) { 
	urls := getImages(url)
	for _, url := range urls { 
		chanImageUrls <- url
	}
	chanTask <- url
	wg.Done()

}

//获取当前页面图片链接
func getImages(url string) (urls []string) { 
	pageStr := getResByPage(url)
	re := regexp.MustCompile(reImage)
	result := re.FindAllStringSubmatch(pageStr, -1)
	for _, res := range result { 
		url := res[0]
		urls = append(urls, url)
	}
	return urls
}

3.结果

总结

睡觉

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服