Как часть сценария 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 Марка Нидхэма в блоге Марка Нидхэма . |