同事写的一段代,码业务场景:需要多次GET请求一个三方服务的http 接口,获取数据后写入文件。发现有部分文件没有写入。查看日志出现了报错“socket: too many open files”、“too many open files”。

在此记录一下解决办法。这也是新写Go的人很常见的问题。

示例代码:

package main

import (
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
) func main() {
requestAndWriteFile()
} // 从接口获取数据并且写入文件
func requestAndWriteFile() {
// 约有5千个元素
params := []string{
"001",
"002",
"003",
"004",
}
hostname := "https://test.com/api"
for _, val := range params {
url := hostname + "?=code" + val
byteData, err := Get(url)
if err != nil{
fmt.Println(err)
continue
}
fileFullPath := "/var/" + val + ".txt"
path := filepath.Dir(fileFullPath)
_, err = os.Stat(path)
// 不存在则创建
if err != nil {
err = os.MkdirAll(path, 0755)
if err != nil {
fmt.Println("创建目录错误", err)
continue
}
}
file, e := os.OpenFile(fileFullPath, os.O_RDWR|os.O_CREATE, 0766)
// 关闭文件
defer file.Close()
if e != nil {
fmt.Println("打开目录错误", e)
}
_, er := file.Write(byteData)
if er != nil {
fmt.Println("写入文件错误", er)
}
} } // 发送GET请求
func Get(url string) ([]byte, error) {
response, err := http.Get(url)
if err != nil {
return nil, err
}
// 关闭响应
defer response.Body.Close()
return ioutil.ReadAll(response.Body)
}

上面的代码中使用了“defer response.Body.Close()” 关闭了http响应体,打开的文件也用“defer file.Close()”关闭了。乍一看似乎没有问题。但是Go的HTTP请求本身是有坑的,释放不及时,会造成同时有多个socket连接。第二个问题就是“defer file.Close()” 写在for 循环中,那么按照defer的特性,将在函数requestAndWriteFile return之前执行多个defer,越先出现的defer越后执行。多次循环后打开的文件数就超过了系统限制,就会报错“too many open files”。

解决办法是:对于http请求导致“socket: too many open files”,采用公用的 http.Transport;对于“too many open files”,写入文件的操作,封装成函数,在函数中打开关闭文件,就可以避免。修改后的示例代码:

package main

import (
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
) // 全局 transport
var globalTransport *http.Transport func init() {
globalTransport = &http.Transport{}
} func main() {
requestAndWriteFile()
} func requestAndWriteFile() {
// 约有5千个元素
params := []string{
"001",
"002",
"003",
"004",
}
hostname := "https://test.com/api"
for _, val := range params {
url := hostname + "?=code" + val
byteData, err := Get(url)
if err != nil{
fmt.Println(err)
continue
}
fileFullPath := "/var/" + val + ".txt"
writeFile(fileFullPath, byteData)
} } func writeFile(fileFullPath string, byteData []byte) error {
path := filepath.Dir(fileFullPath)
_, err := os.Stat(path)
// 不存在则创建
if err != nil {
err = os.MkdirAll(path, 0755)
if err != nil {
fmt.Println("创建目录错误")
return err
}
}
file, e := os.OpenFile(fileFullPath, os.O_RDWR|os.O_CREATE, 0766)
// 一定要close
defer file.Close()
if e != nil {
fmt.Println("打开目录错误")
}
_, er := file.Write(byteData)
if er != nil {
fmt.Println("写入文件错误")
return er
} return nil
} // 发送get请求
func Get(uri string) ([]byte, error) {
client := http.Client{
Transport: globalTransport,
}
res, err := client.Get(uri)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
} return body, nil }

如果确实有必要同时打开超过系统限制的多个文件,那么可以使用ulimit 命令修改。

golang 解决 socket: too many open files, 以及 too many open files的更多相关文章

  1. C#下利用封包、拆包原理解决Socket粘包、半包问题(新手篇)

    介于网络上充斥着大量的含糊其辞的Socket初级教程,扰乱着新手的学习方向,我来扼要的教一下新手应该怎么合理的处理Socket这个玩意儿. 一般来说,教你C#下Socket编程的老师,很少会教你如何解 ...

  2. 解决Socket粘包问题——C#代码

    解决Socket粘包问题——C#代码 前天晚上,曾经的一个同事问我socket发送消息如果太频繁接收方就会有消息重叠,因为当时在外面,没有多加思考 第一反应还以为是多线程导致的数据不同步导致的,让他加 ...

  3. 切实解决socket连接掉线检测

    原文:切实解决socket连接掉线检测 版权声明:欢迎转载,但是请保留出处说明 https://blog.csdn.net/lanwilliam/article/details/51698807 新公 ...

  4. 14.7.2 Changing the Number or Size of InnoDB Redo Log Files 改变InnoDB Redo Log Files的数量和大小

    14.7.2 Changing the Number or Size of InnoDB Redo Log Files 改变InnoDB Redo Log Files的数量和大小 改变 InnoDB ...

  5. 14.5.2 Changing the Number or Size of InnoDB Redo Log Files 改变InnoDB Redo Log Files的数量

    14.5.2 Changing the Number or Size of InnoDB Redo Log Files 改变InnoDB Redo Log Files的数量 改变InnoDB redo ...

  6. 解决Socket.IO在IE8下触发disconnect时间过长

    本文地址: http://www.cnblogs.com/blackmanba/p/solve-socketIO-IE8-emit-disconnect-too-long.html或者http://f ...

  7. golang 解决 TCP 粘包问题

    什么是 TCP 粘包问题以及为什么会产生 TCP 粘包,本文不加讨论.本文使用 golang 的 bufio.Scanner 来实现自定义协议解包. 协议数据包定义 本文模拟一个日志服务器,该服务器接 ...

  8. 解决 LLVM 错误 cannot specify -o when generating multiple output files

    Xcode 9 使用 LLVM 混淆器会提示错误: clang: error: cannot specify -o when generating multiple output files 通过对比 ...

  9. 解决socket负载均衡集群方案和代码实现

    有一段时间,在考虑下socket 之间集群 可以在Nginx 下可以 但是不同服务器之间怎么通讯呢 后来自己也想可不可以用什么东西或者中间件来通讯 ,后来在百度之下 发现果然就是按照我所想的 ,在网上 ...

  10. 解决socket粘包的两种low版模式 os.popen()和struct模块

    os.popen()模式 server端 import socket import os phone = socket.socket() # 实例化一个socket对象 phone.bind((&qu ...

随机推荐

  1. 将pyinstaller打包的exe文件制作成安装包

    1. 下载安装 inno setup (下载地址:http://www.jrsoftware.org/isdl.php) 2. 配置inno setup中文语言包 inno setup默认并没有中文, ...

  2. locust自定义负载策略。

    1.时间峰值策略 每运行一分钟启动100个用户,总运行时间为10分钟 class CustomShape(LoadTestShape): # 设置时限 time_limit = 600 # 设置产生率 ...

  3. 如何实现基于GPIO按键的长按,短按,双击

    不同的架构实现并不相同,所以我分成了两中:STM32平台和其他平台: STM32平台 首先要分析:该如何判断当前的按键状态:单机和双击是通过在有限时间内是否有新的按动作产生 -- 所以需要一个记录按键 ...

  4. element table组件列表固定列后横向滚动条的问题

    使用el-table的fixed属性固定表格列的时候滚动条被固定列覆盖部分无法拖动 可以使用下面配置来解决 .el-table__fixed { height: auto !important; // ...

  5. JavaScript案例:倒计时

    展示效果: 代码示例: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...

  6. PY3多继承

    __author__ = "Alex Li"class A: def __init__(self): print("A")class B(A): pass #d ...

  7. Python异步爬取梁羽生小说网

    才知道写在文章里面不是原创... https://www.cnblogs.com/kebei/articles/14659937.html

  8. 001 jmete文件目录介绍及汉化

    1.Jmeter文件目录介绍 1.1 bin目录:存放可执行文件和配置文件 jmeter.bat:windows的启动文件 jmeter.log:日志文件 jmeter.sh:linux的启动文件 j ...

  9. Ehlib的DBGridEh 控件导出到Excel

    use DBGridEhImpExp //必须引用此单元 procedure TInvoiceManager.ppmSaveSelectionClick(Sender: TObject); proce ...

  10. vi中将小写转换成大写字母

    VI阅读模式下连续按gUW可以将小写转换成大写