Как часть сценария Go, над которым я работал, я хотел записать в файл CSV несколько процедур Go, но понял, что встроенный модуль записи CSV не является поточно-ориентированным.
Моя первая попытка записи в файл CSV выглядела так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
package main import ( "encoding/csv" "os" "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 }(i) } for i:= 0 ; i < count; i++ { <- done } w.Flush() } |
основной импорт пакета («encoding / csv» «os» «log» «strconv») func main () {csvFile, err: = os.Create («/ tmp / foo.csv»), если err! = nil {log. Panic (err)} w: = csv.NewWriter (csvFile) w.Write ([] string {“id1 ″,” id2 ″, ”id3”}) count: = 100 done: = make (chan bool, count) для я: = 0; я <считать; i ++ {go func (i int) {w.Write ([] string {strconv.Itoa (i), strconv.Itoa (i), strconv.Itoa (i)}) done <- true} (i)} для i : = 0; я <считать; i ++ {<- done} w.Flush ()}
Этот скрипт должен выводить числа от 0 до 99 три раза в каждой строке. Некоторые строки в файле написаны правильно, но, как мы видим ниже, некоторые нет:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
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 74 7779^@,79,77 ... |
Один из способов сделать наш сценарий безопасным — это использовать мьютекс всякий раз, когда мы вызываем какие-либо методы в модуле записи CSV. Я написал следующий код для этого:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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, а затем используем его в функциях Write и Flush, так что только одна подпрограмма go может одновременно получить доступ к базовому CsvWriter . Затем мы настраиваем начальный скрипт для вызова этого класса вместо прямого вызова CsvWriter:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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 }(i) } for i:= 0 ; i < count; i++ { <- done } w.Flush() } |
И теперь, если мы проверим файл CSV, все строки были успешно написаны:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
... 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 ... |
Это все на данный момент. Если у вас есть предложения для лучшего способа сделать это, дайте мне знать в комментариях или в твиттере — я @markhneedham
Будьте общительны, делитесь!
Ссылка: | Go: Многопоточная запись в файл CSV от нашего партнера по JCG Марка Нидхэма в блоге Марка Нидхэма . |