#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:
Проблема в том, что у вас есть несколько программ, пытающихся выполнить запись в файл одновременно, без какой-либо синхронизации. Это приведет к непредсказуемому порядку вывода и, возможно, к потере записей. Использование буферизованного ввода-вывода в дополнение к этому просто помогает скрыть поведение.
Лучшее решение — запустить единственную подпрограмму, которая выполняет запись на ваш вывод (с буферизованным вводом-выводом или без него, в зависимости от ваших потребностей), и заставить всех ваших рабочих отправлять данные для записи в пишущую подпрограмму по каналу.