同事写的一段代,码业务场景:需要多次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. ggplot2绘制饼图

    # 加载 ggplot2 包 library(ggplot2) # 加载数据 data <- data.frame(category = c("A", "B&quo ...

  2. 若依gateway

    1.若依后端gateway模块配置白名单 顾名思义,就是允许访问的地址.且无需登录就能访问.在ignore中设置whites,表示允许匿名访问. 2. SpringCloud Gateway网关配置( ...

  3. redisTemplate实现分布式锁(释放锁用lua脚本)

    package com.xxx.platform.util; import org.springframework.beans.factory.annotation.Autowired; import ...

  4. EF中使用SqlBulkCopy

    using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using S ...

  5. “初始化 Java 工具”期间发生了内部错误, java.lang.NullPointerException

    今天刚打开eclipse就报了这个错误,我怀疑是昨晚想关电脑的时候,关闭eclipse太快,没有等待工作空间保存就关了电脑的缘故 错误如图: (图片来自下方链接博客,因为忘记截图了) 我百度后按照提示 ...

  6. Flink1.10定义UDAGG遇到SQL validation failed. null 问题

    按照以下代码测试定义的UDAGG会一直出现org.apache.flink.table.api.ValidationException: SQL validation failed. null 问题 ...

  7. 固定代码格式化程序插件-Prettier JetBrains

    基本使用 使用npm install prettier --save-dev为您的项目添加更漂亮或全局安装 使用Prettier选择要格式化的代码或文件 使用"Reformat with P ...

  8. 对词向量模型Word2Vec和GloVe的理解

    Word2Vec Word2Vec 是 google 在2013年提出的词向量模型,通过 Word2Vec 可以用数值向量表示单词,且在向量空间中可以很好地衡量两个单词的相似性. 简述 我们知道,在使 ...

  9. java中indexOf()获取指定次数的下标

    indexOf() :指定字符在此实例中的第一个匹配项的索引.搜索从指定字符位置开始,并检查指定数量的字符位置 Java中提供了四中查找方法: int indexOf(String str) 返回第一 ...

  10. SpringCloudEureka上篇

    SpringCloudEureka上篇 本文学习自<<重新定义SpringCloud>> Eureka简介 Eureka是Netflix公司开源的一款服务发现组件,该组件提供的 ...