Как часть сценария 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,4037,37,3738,38,3818,18,39^@,39,39...67,67,70,^@70,7065,65,6573,73,7366,66,6672,72,7275,74,75,74,75747779^@,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,2513,13,1329,29,2932,32,3226,26,2630,30,3027,27,2731,31,3128,28,2834,34,3435,35,3533,33,3337,37,3736,36,36... |
Это все на данный момент. Если у вас есть предложения для лучшего способа сделать это, дайте мне знать в комментариях или в твиттере — я @markhneedham
Будьте общительны, делитесь!
| Ссылка: | Go: Многопоточная запись в файл CSV от нашего партнера по JCG Марка Нидхэма в блоге Марка Нидхэма . |