2017-01-30 1 views
1

Вот моя отправная точка.Используя Golang для чтения csv, переупорядочивайте столбцы, затем записывайте результат в новый csv с Concurrency

Это скрипт Golang для чтения в csv с тремя столбцами, переупорядочение столбцов и запись результата в новый файл csv.

package main 

import (
    "fmt" 
    "encoding/csv" 
    "io" 
    "os" 
    "math/rand" 
    "time" 
) 

func main(){ 
    start_time := time.Now() 

    // Loading csv file 
    rFile, err := os.Open("data/small.csv") //3 columns 
    if err != nil { 
    fmt.Println("Error:", err) 
    return 
    } 
    defer rFile.Close() 

    // Creating csv reader 
    reader := csv.NewReader(rFile) 

    lines, err := reader.ReadAll() 
    if err == io.EOF { 
     fmt.Println("Error:", err) 
     return 
    } 

    // Creating csv writer 
    wFile, err := os.Create("data/result.csv") 
    if err != nil { 
     fmt.Println("Error:",err) 
     return 
    } 
    defer wFile.Close() 
    writer := csv.NewWriter(wFile) 

    // Read data, randomize columns and write new lines to results.csv 
    rand.Seed(int64(time.Now().Nanosecond())) 
    var col_index []int 
    for i,line :=range lines{ 
     if i == 0 { 
     //randomize column index based on the number of columns recorded in the 1st line 
     col_index = rand.Perm(len(line)) 
    } 
    writer.Write([]string{line[col_index[0]], line[col_index[1]], line[col_index[2]]}) //3 columns 
    writer.Flush() 
} 

//print report 
fmt.Println("No. of lines: ",len(lines)) 
fmt.Println("Time taken: ", time.Since(start_time)) 

} 

Вопрос:

  1. Является ли мой код идиоматических для Golang?

  2. Как добавить параллелизм к этому коду?

+1

Вы не можете читать или писать отдельные файлы одновременно, и когда обработка данных будет намного быстрее, чем IO, мало что может сделать при чтении одного файла одновременно с написанием другого. Если файлы огромны, это может стоить того, но сначала получите рабочий пример, чтобы понять основы. – JimB

+3

Это может быть лучше подходит для [codereview.stackexchange.com] (http://codereview.stackexchange.com/). – icza

+0

@JimB А, я не знал, что чтение/запись файлов не может быть выполнено одновременно. Если я выделил свою рандомизацию столбцов как отдельный метод, например. func RandomizeColumns ([] string), могу ли я разделить объект Reader на 2 потока и применить RandomizeColumns() одновременно? I.e. Можно ли разбить объект csv.Reader() на 2? –

ответ

0

Ваш код в порядке. Нет много случаев для параллелизма. Но вы, по крайней мере, можете сократить переупорядочение потребления памяти на лету. Просто используйте Read() вместо ReadAll(), чтобы избежать выделения среза для входного файла отверстия.

for line, err := reader.Read(); err == nil; line, err = reader.Read(){ 
    if err = writer.Write([]string{line[col_index[0]], line[col_index[1]], line[col_index[2]]}); err != nil { 
      fmt.Println("Error:", err) 
      break 
    } 
    writer.Flush() 
} 
+0

Спасибо за улучшение! Я считаю ваш ответ адекватным ответом на мой вопрос. Я немного разочарован тем, что для этого варианта использования нет необходимости в параллелизме, но я пойду искать другое упражнение, чтобы практиковать это. –

0

Перемещение col_index инициализации вне цикла записи:

if len(lines) > 0 { 
    //randomize column index based on the number of columns recorded in the 1st line 
    col_index := rand.Perm(len(lines[0])) 
    newLine := make([]string, len(col_index)) 

    for _, line :=range lines[1:] { 
     for from, to := range col_index { 
      newLine[to] = line[from] 
     } 
     writer.Write(newLine) 
     writer.Flush() 
    } 
} 

Чтобы использовать параллелизм, вы не должны использовать reader.ReadAll. Вместо этого сделайте goroutine, который вызывает reader.Read и напишите вывод на канале, который заменит массив lines. Главный горутин будет читать канал и делать перетасовку и писать.

+0

Благодарим вас за то, что нашли время, чтобы просмотреть мой код + объяснить возможное решение, включающее параллелизм. –

Смежные вопросы