添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

作为Go脚本的一部分,我一直在努力,我想从多个Go例程中写入CSV文件,但是意识到内置的CSV Writer不是线程安全的。

我第一次写入CSV文件的尝试如下所示:

package main
import (
	"encoding/csv"
	"log"
	"strconv"
func main() {
	csvFile, err := os.Create("/tmp/foo.csv")
	if err != nil {
		log.Panic(err)
	w := csv.NewWriter(csvFile)
	w.Write([]string{"id1","id2","id3"})
	count := 100
	done := make(chan bool, count)
	for i := 0; i < count; i++ {
		go func(i int) {
			w.Write([]string {strconv.Itoa(i), strconv.Itoa(i), strconv.Itoa(i)})
			done <- true
	for i:=0; i < count; i++ {
		<- done
	w.Flush()
 

包main import(“ encoding / csv”“ os”“ log”“ strconv”)func main(){csvFile,err:= os.Create(“ / tmp / foo.csv”)如果err!= nil {日志。 Panic(err)} w:= csv.NewWriter(csvFile)w.Write([] string {“ id1”,“ id2”,“ id3”})count:= 100完成:= make(chan bool,count)为i:= 0; 我<数; i ++ {go func(i int){w.Write([] string {strconv.Itoa(i),strconv.Itoa(i),strconv.Itoa(i)})为我完成了<-true}(i)} := 0; 我<数; i ++ {<-完成} w.Flush()}

该脚本应在每行上输出0-99之间的数字三次。 文件中的某些行已正确写入,但是如下面所示,有些行却不是:

40,40,40
37,37,37
38,38,38
18,18,39
^@,39,39
67,67,70,^@70,70
65,65,65
73,73,73
66,66,66
72,72,72
75,74,75,74,75
7779^@,79,77
 

确保脚本安全的一种方法是,只要在CSV编写器上调用任何方法,就使用互斥量。 我编写了以下代码来做到这一点:

type CsvWriter struct {
	mutex *sync.Mutex
	csvWriter *csv.Writer
func NewCsvWriter(fileName string) (*CsvWriter, error) {
	csvFile, err := os.Create(fileName)
	if err != nil {
		return nil, err
	w := csv.NewWriter(csvFile)
	return &CsvWriter{csvWriter:w, mutex: &sync.Mutex{}}, nil
func (w *CsvWriter) Write(row []string) {
	w.mutex.Lock()
	w.csvWriter.Write(row)
	w.mutex.Unlock()
func (w *CsvWriter) Flush() {
	w.mutex.Lock()
	w.csvWriter.Flush()
	w.mutex.Unlock()
 

NewCsvWriter实例化CsvWriter并在WriteFlush函数中使用它时,我们将创建一个互斥锁,以便一次只能执行一个go例程来访问基础CsvWriter 。 然后,我们调整初始脚本以调用此类,而不是直接调用CsvWriter:

func main() {
	w, err := NewCsvWriter("/tmp/foo-safe.csv")
	if err != nil {
		log.Panic(err)
	w.Write([]string{"id1","id2","id3"})
	count := 100
	done := make(chan bool, count)
	for i := 0; i < count; i++ {
		go func(i int) {
			w.Write([]string {strconv.Itoa(i), strconv.Itoa(i), strconv.Itoa(i)})
			done <- true
	for i:=0; i < count; i++ {
		<- done
	w.Flush()
 

现在,如果我们检查CSV文件,则所有行均已成功写入:

25,25,25 13,13,13 29,29,29 32,32,32 26,26,26 30,30,30 27,27,27 31,31,31 28,28,28 34,34,34 35,35,35 33,33,33 37,37,37 36,36,36

目前为止就这样了。 如果您对更好的方法有任何建议,请在评论中或在Twitter上告诉我–我是@markhneedham

善于交际,分享!

翻译自: https://www.javacodegeeks.com/2017/01/go-multi-threaded-writing-csv-file.html

数据组同事需要一个小工具帮组他们处理一些数据。首先他们的原数据是csv文件的,需要我们把里面的数据和别的系统里面的数据逐条匹配完善后返回给他们一个csv文件。原数据的csv一般3-5万条数据量(单列的)。 解决方案: 首先读取csv文件,生成待处理数据集合。然后把该数据集合分片,以使用多线程进行匹配处理。最后通过POI生成csv输出。(一开始同事没有使用多线程,虽然数据量不算大,但是... Service Mesh技术作为新一代微服务架构,有效的解决了当前微服务架构和治理过程中的痛点问题,一经推出便引起很大的反响,近两年持续成为架构领域的热点。特别是Google联合Lyft等公司推出的Istio,架构优雅,功能强大,迅速成为Service Mesh领域的明星项目。 什么是Service Mesh 作为Service Mesh技术探索和实践的先行者,全球第一个真正的Se... 前言:当遇到大量数据导入时,为了提高处理的速度,可以选择使用多线程来批量处理这些处理。常见的场景有:大文件导入数据库(这个文件不一定是标准的CSV可导入文件或者需要在内存中经过一定的处理)数据同步(从第三方接口拉取数据处理后写入自己的数据库)以上的场景有一个共性,这类数据导入的场景简单来说就是将数据从一个数据源移动到另外一个数据源,而其中必定可以分为两步数据读取:从数据源读取数据到内存数据写入:将... import java.io.File; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.List; impor 第一步:目标站点分析 url = ‘http://sou.zhaopin.com/jobs/searchresult.ashx?p=0&jl=%E5%85%A8%E5%9B%BD&kw=%E5%A4%A7%E6%95%B0%E 从数据库导出数据到csv文件的时候,采用默认的utf-8编码导致用默认程序excel打开乱码。原因是程序运行在windows系统,文件使用utf-8写入保存的时候系统使用utf-8-bom编码。只要把文件转为utf-8... 最近接到一项工作,是要计算某个省的所有县,两两之间的距离。这个排列组合大约有2万条记录。我采取的是百度地图API来查询两个县之间的距离。由于访问百度地图API请求数据,需要一定的时间,所以考虑使用java的线程池创建多线程来完成这一项工作,一边去baidu地图查询结果,一边向CSV文件写入数据。 代码如下: //用队列存放每一个线程执行的结果值。 Queue result  = new L