BufferedWriter не работает при одновременном использовании

#go #concurrency #writer #buffered

#Вперед #параллелизм #writer #буферизованный

Вопрос:

Мне нужно записать большой объем данных в текстовый файл из нескольких программ (скажем, 30) одновременно. Что я делаю, так это:

 workers.Add(core.Concurrency)
    for i := 0; i < core.Concurrency; i   {
        go func() {
            defer workers.Done()
            writer := bufio.NewWriter(f)
            defer writer.Flush()
            a.Worker(workChan, writer)
        }()
    }
  

Но, похоже, это не работает в некоторых случаях. Вот f это *os.File объект. В некоторых случаях запись в файл вообще не выполняется, а в некоторых случаях записываются некоторые данные, но не выполняются последующие записи. Поведение очень непоследовательное, и ошибок тоже нет.

Есть идеи, почему это может происходить?

Комментарии:

1. @Flimzy Это имеет смысл, я полагал, что это связано с параллелизмом. Я нашел это — github.com/free/concurrent-writer . Собираюсь попробовать

2. Потому что bufio. Запись сбрасывается, когда буфер заполнен, данные записываются в непредсказуемом порядке в f . Есть способы исправить это. Дайте некоторые подробности о том, что пишет приложение (записывает ли приложение какие-либо записи с разделителями, насколько велики записи, …)

3. @Flimzy У меня есть несколько программ записи, потому что данные, которые необходимо проанализировать, довольно большие, на самом деле это большое количество dns-имен, которые удаляются с онлайн-ресурса, поэтому я хотел использовать несколько программ записи, чтобы увеличить скорость. Я думаю, что single writer тоже не так уж плох.

4. Приложение @ThunderCat записывает имена хостов в файл с разделением на новую строку, и да, файл незащищен. Я думаю, что глобального мьютекса в файле было бы достаточно.

5. @Flimzy На самом деле это имеет смысл, я выберу один writer. Спасибо за вашу помощь.

Ответ №1:

Проблема в том, что у вас есть несколько программ, пытающихся выполнить запись в файл одновременно, без какой-либо синхронизации. Это приведет к непредсказуемому порядку вывода и, возможно, к потере записей. Использование буферизованного ввода-вывода в дополнение к этому просто помогает скрыть поведение.

Лучшее решение — запустить единственную подпрограмму, которая выполняет запись на ваш вывод (с буферизованным вводом-выводом или без него, в зависимости от ваших потребностей), и заставить всех ваших рабочих отправлять данные для записи в пишущую подпрограмму по каналу.