首页
关于
统计
友链
更多
留言
Search
1
Golang 语言中的 chan 通道
1,059 阅读
2
ThinkPHP 关闭缓存
845 阅读
3
Python简单爬虫(XHS)
815 阅读
4
简单的Python爬虫代码演示
796 阅读
5
【油猴插件推荐】可显示抖音直播间实际人数
726 阅读
前端
Vue
Uni-app
Layui
Element-ui
后端
PHP
Goalng
Python
Linux
Docker
Mysql
Redis
算法
硬件
NAS
路由器
交换机
教程
杂谈
家庭网络
乱七八糟
智能家居
登录
Search
标签搜索
golang
goroutine
并发
chan
xiaomi
小米
智能家居
摄像机
家庭监控
油猴插件
CodeMan
累计撰写
14
篇文章
累计收到
6
条评论
首页
栏目
前端
Vue
Uni-app
Layui
Element-ui
后端
PHP
Goalng
Python
Linux
Docker
Mysql
Redis
算法
硬件
NAS
路由器
交换机
教程
杂谈
家庭网络
乱七八糟
智能家居
页面
关于
统计
友链
留言
搜索到
6
篇与
的结果
2023-03-28
Golang 语言中的 chan 通道
Golang 语言中的 chan 通道在并发编程中扮演着重要角色,通过它可以在不同的 Goroutine 之间传递数据。然而,在实际使用过程中,可能会遇到一些 chan 使用上的问题。本文将介绍一些常见的 chan 使用陷阱以及如何避免它们。1. 未初始化的 chan在使用 chan 之前,必须对其进行初始化。如果直接使用一个未初始化的 chan,会导致运行时 panic。例如:func main() { var ch chan int ch <- 1 // 这里会导致 panic }解决方案:使用 make 函数初始化 chan:func main() { ch := make(chan int) ch <- 1 }2. 阻塞式读取 chan向一个已满的 chan 中写入数据或者从一个空的 chan 中读取数据都会导致 Goroutine 阻塞。这可能会导致死锁或者程序无法继续运行。例如:func main() { ch := make(chan int) ch <- 1 ch <- 2 // 这里会阻塞,因为 ch 默认是无缓冲的 }解决方案:使用带缓冲的 chan 或者使用 select 语句设置默认操作:func main() { ch := make(chan int, 1) ch <- 1 select { case ch <- 2: default: fmt.Println("Channel is full") } }3.关闭已关闭的 chan重复关闭同一个 chan 会导致运行时 panic。例如:func main() { ch := make(chan int) close(ch) close(ch) // 这里会导致 panic }解决方案:确保每个 chan 只关闭一次。可以使用 sync.Once 来实现这个功能:func main() { ch := make(chan int) once := sync.Once{} // 定义一个只执行一次的关闭函数 closeOnce := func() { once.Do(func() { close(ch) }) } closeOnce() closeOnce() // 这里不会导致 panic }4.从已关闭的 chan 中读取数据从一个已关闭的 chan 中读取数据不会导致 panic,但会返回零值。这可能会导致程序逻辑错误。例如:func main() { ch := make(chan int) close(ch) fmt.Println(<-ch) // 这里会输出 0 }解决方案:使用第二个返回值来判断 chan 是否已关闭:func main() { ch := make(chan int) close(ch) if value, ok := <-ch; ok { fmt.Println(value) } else { fmt.Println("Channel is closed") } }5.无法检测 chan 是否已满在某些场景下,我们可能需要检测一个带缓冲的 chan 是否已满。然而,Golang 并没有提供直接的方法来实现这一功能。尝试向一个已满的 chan 中写入数据会导致阻塞。解决方案:使用 select 语句和 default 分支来避免阻塞:func main() { ch := make(chan int, 1) ch <- 1 select { case ch <- 2: fmt.Println("Data sent") default: fmt.Println("Channel is full") } }6.不正确的 chan 使用顺序在使用 chan 时,需要确保正确的发送和接收顺序。错误的顺序可能导致死锁或程序无法继续执行。例如:func main() { ch := make(chan int) go func() { <-ch }() go func() { ch <- 1 }() }解决方案:使用 sync.WaitGroup 或其他同步原语确保正确的执行顺序:func main() { ch := make(chan int) wg := sync.WaitGroup{} wg.Add(1) go func() { <-ch wg.Done() }() wg.Add(1) go func() { ch <- 1 wg.Done() }() wg.Wait() }通过了解和避免这些常见的 chan 使用陷阱,我们可以编写更加健壮和高效的 Golang 并发程序。在实际开发中,要时刻注意这些问题,并在遇到问题时积极寻求解决方案。这样,我们才能充分发挥 Golang 在并发编程方面的优势,提高程序的可维护性和可靠性。
2023年03月28日
1,059 阅读
0 评论
22 点赞
2023-02-18
Golang 并发编程:Goroutine 的坑与解决方案
Go 语言在并发编程领域,Go 语言的 Goroutine 是其最显著的特性之一。然而,在实际工作应用中,可能会遇到一些 Goroutine 使用上的坑。本文就是记录了我在工作中使用 Goroutine 使用陷阱以及如何避免它们。1. Goroutine 泄露Goroutine 泄露是指创建的 Goroutine 没有得到妥善处理,导致无法回收的情况。这可能会导致内存泄露和性能下降。例如:func main() { ch := make(chan int) go func() { ch <- doSomething() // 这里可能会阻塞 }() time.Sleep(1 * time.Second) }解决方案:使用 context 控制 Goroutine 的退出,或者使用 select 语句设置超时:func main() { ch := make(chan int) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) defer cancel() go func() { select { case ch <- doSomething(): case <-ctx.Done(): } }() time.Sleep(1 * time.Second) }2. 不同步的访问共享数据当多个 Goroutine 同时访问共享数据时,如果没有进行同步操作,可能会导致数据竞争和不可预测的结果。例如:var counter int func main() { wg := sync.WaitGroup{} for i := 0; i < 1000; i++ { wg.Add(1) go func() { counter++ wg.Done() }() } wg.Wait() fmt.Println(counter) }解决方案:使用 sync.Mutex 互斥锁或者 sync/atomic 原子操作进行同步:var counter int64 func main() { wg := sync.WaitGroup{} for i := 0; i < 1000; i++ { wg.Add(1) go func() { atomic.AddInt64(&counter, 1) wg.Done() }() } wg.Wait() fmt.Println(counter) }3. Goroutine 数量过多创建过多的 Goroutine 可能会导致内存耗尽和性能下降。例如,在处理大量任务时,我们不应该为每个任务创建一个 Goroutine。解决方案:使用 sync.WaitGroup 和有缓冲的 channel 限制 Goroutine 的数量:func main() { tasks := make(chan int, 100) wg := sync.WaitGroup{} // 创建 10 个工作 Goroutine for i := 0; i < 10; i++ { go func() { for task := range tasks { processTask(task) wg.Done() }() } // 添加任务到 channel for i := 0; i < 1000; i++ { tasks <- i wg.Add(1) } // 关闭任务 channel 并等待所有 Goroutine 完成 close(tasks) wg.Wait()4. 不正确的错误处理在 Goroutine 中处理错误时,需要确保错误能被正确捕获和处理。例如,以下代码中的错误无法正确传递给主 Goroutine:func main() { go func() { if err := doSomething(); err != nil { log.Fatal(err) } }() time.Sleep(1 * time.Second) }解决方案:使用 channel 将错误传递回主 Goroutine 进行处理:func main() { errCh := make(chan error) go func() { if err := doSomething(); err != nil { errCh <- err } close(errCh) }() for err := range errCh { if err != nil { log.Fatal(err) } } }总结Golang 的 Goroutine 提供了强大的并发能力,但在使用过程中需要注意一些坑,如 Goroutine 泄露、不同步访问共享数据、过多的 Goroutine 以及错误处理。通过学习这些常见的陷阱及其解决方案,我们可以更有效地利用 Goroutine 进行并发编程,提高程序的稳定性和性能。
2023年02月18日
626 阅读
0 评论
13 点赞
2021-08-24
Python简单爬虫(XHS)
用的是小程序版本+fd抓包抓的接口+Python的requests模块,爬完后自动保存到Mysql数据库,会PHP的,可以整理成自己想要的数据代码大致如下:隐藏内容,请前往内页查看详情
2021年08月24日
815 阅读
0 评论
20 点赞
2021-08-03
使用docker部署selenium+chrome-headless
有一个docker镜像叫做selenium/standalone-chrome。可以直接远程调用webdriver控制chrome。{mtitle title="安装方式"/}docker run -d -p 4444:4444 --shm-size=2g selenium/standalone-chrome:3.141.59-dubnium{mtitle title="启动selenium"/}docker run -d -p 4444:4444 --shm-size=2g selenium/standalone-chrome{mtitle title="连接代码模板"/}from selenium import webdriver from selenium.webdriver.common.desired_capabilities import DesiredCapabilities driver = webdriver.Remote( command_executor="http://8.8.8.8:4444/wd/hub", desired_capabilities=DesiredCapabilities.CHROME ) driver.get("http://www.baidu.com") print(driver.title) driver.close()
2021年08月03日
608 阅读
0 评论
13 点赞
2021-07-08
简单的Python爬虫代码演示
# auther : keepython import requests from lxml import etree import time import re # 可可英语文章爬虫 def seconde_spider(page_url): page_html = requests.get(page_url) # 用index_spider传入的文章地址开始爬取文章内容 page_html.encoding = 'utf-8' # 使用utf8形式进行编码 selector = etree.HTML(page_html.text) # 将编码后的网页内容处理为可以进行xpath筛选的形式 title = selector.xpath('//h1[@id="nrtitle"]/text()')[0] # 爬取文章的标题 txt_file = title + '.txt' # 使用字符串拼接的形式构建文件名称 eng_text = selector.xpath('//div[@class="qh_en"]/p/text()') # 提取英文文章内容 ch_text = selector.xpath('//div[@class="qh_zg"]/p/text()') # 提取中文文章内容 time_stamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) # 使用time模块以对应的年-月日 小时 分钟 秒的形式 file_path = '.\\data\\keke\\' + txt_file # 构建文章地址,注意这里是绝对路径因为在centos中定时任务只能读取绝对路径 with open(file_path, 'a') as f: # 用with open的形式创建并打开文件 # 接下来就是将爬取到的文章内容写入对应的txt文档中 f.write(title) f.write('\n') f.write(time_stamp) f.write('\n') for i in eng_text: f.write(i) f.write('\n') f.write('\n\n') for j in ch_text: f.write(j) f.write('\n') return file_path # 返回文档的路径 # 沪江英语文章爬虫,内容基本相同 def hujiang_second_spider(page_url): page_html = requests.get(page_url) page_html.encoding = 'utf-8' selector = etree.HTML(page_html.text) title = selector.xpath('//h1[@class="title"]/text()')[0] txt_file = title + '.txt' # eng_title = selector.xpath('//div[@class="langs_en"]/strong/text()')[0] eng_text = selector.xpath('//div[@class="langs_en"]/text()|//div[@class="langs_en"]/strong/text()') ch_text = selector.xpath('//div[@class="langs_cn"]/text()|div[@class="langs_cn"]/strong/text()') time_stamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) file_path = './data/hujiang/' + txt_file with open(file_path, 'a') as f: f.write(title) f.write('\n') f.write(time_stamp) f.write('\n') for i in eng_text: f.write(i) f.write('\n') f.write('\n\n') for j in ch_text: f.write(j) f.write('\n') return file_path
2021年07月08日
796 阅读
0 评论
14 点赞
2021-04-15
ThinkPHP 关闭缓存
全局请求缓存 如果需要开启全局请求缓存,只需要在全局(或者应用)的中间件定义文件middleware.php中增加 'think\middleware\CheckRequestCache', 然后只需要在route.php配置文件中设置全局缓存的有效时间(秒): 'request_cache_expire' => 3600, 就会自动根据当前请求URL地址(只针对GET请求类型)进行请求缓存,全局缓存有效期为3600秒。 如果需要对全局缓存设置缓存规则,可以直接设置request_cache_key参数,例如: 'request_cache_key' => '__URL__', 'request_cache_expire' => 3600,
2021年04月15日
845 阅读
0 评论
15 点赞