Господа, прошу подсказать. Этой функцией я записываю текущую маркет дату
Код
function rec_big_data(file_path,value)
if rn==nil then rn={} end
if file_open==nil then file_open={} end
if file_open[file_path]==nil then
rn[file_path]=io.open(file_path,"a+")
file_open[file_path]=true
mm("QL:open file "..file_path)
end
rn[file_path]:write(value.."\n")
rn[file_path]:flush()
end
file_path меняется три раза в день (в его название включён тикер, текущая дата и номер триместра: утренняя сессия 1, дневная сессия 2, вечерняя сессия 3). вот пример historyGDM8 20180511-2.lua В функции нет закрытия файла, потому что файл становится огромным, и скрипту тяжело его постоянно открывать-закрывать. Робот пишет большое количество инструментов много дней подряд. Файлы остаются открытыми. Я замечаю, что виртуалка начинает тормозить. Думаю, что это из-за незакрытых файлов. Подскажите пожалуйста как грамотно закрывать файл в конце триместра (при переходе на новый файл) с помощью close()? Не могу сообразить, что в неё писать. Спасибо.
Таблица дескрипторов файлов (rn) у Вас - глобальная. Где-то вне функции rec_big_data Ваш скрипт, судя по всему, в нужный момент понимает, что нужно сменить номер триместра. Что Вам мешает в этот момент просто позакрывать все файлы, зная их дескрипторы из таблицы rn?
Спасибо за ответы. Разрешите задать ещё вопрос. Я открыл файл с помощью io.open. После этого я остановил скрипт. Файл останется открытым, верно? Если да, то следующий вопрос. Я запустил скрипт и снова открыл этот же файл с помощью io.open. Теперь у меня два открытых файла? --- И ещё один вопрос. Как мне принудительно закрыть файл, имея не дескриптор, а только путь file_path? --
Как мне отлавливать средствами Луа, Windows или специальных программ открытые в данный момент луа-файлы? В Windows server 2003 эта функция не работает и не лечится. Я искал советы по данной проблеме, но они не сработали.
Алексей написал: Таблица дескрипторов файлов (rn) у Вас - глобальная. Где-то вне функции rec_big_data Ваш скрипт, судя по всему, в нужный момент понимает, что нужно сменить номер триместра. Что Вам мешает в этот момент просто позакрывать все файлы, зная их дескрипторы из таблицы rn?
Добавил в функцию переменную files_qty - это количество бумаг, которые пишутся. Если размер таблицы rn больше files_qty, значит сменился триместр и надо закрывать старые файлы. Очевиден недостаток: при смене триместра функция один раз закроет хороший файл - файл новенького триместра. Потом ей придётся его переоткрывать.
Let_it_go написал: В Windows server 2003 эта функция не работает и не лечится. Я искал советы по данной проблеме, но они не сработали.
Вы не то смотрите. Эта оснастка «Общие папки» показывает файлы открытые по сети (по протоколу SMB), и это никакого отношения к файловой системе и файлом открытым локально не имеет. Оснастка у вас не работает скорее всего, если мне не изменяет память, потому что не запущена одна из служб, на подобие «Files and Folder bla bla bla» или что-то вроде того... чтобы посмотреть системные ресурсы открытые конкретным процессом, в том числе и файлы, используйте Process Explorer.
Цитата
Let_it_go написал: Добавил в функцию переменную files_qty - это количество бумаг, которые пишутся. Если размер таблицы rn больше files_qty, значит сменился триместр и надо закрывать старые файлы. Очевиден недостаток: при смене триместра функция один раз закроет хороший файл - файл новенького триместра. Потом ей придётся его переоткрывать.
1. Файл закрывайте там, где вы определяете смену «триместра», то-есть там, где у вас создаётся новая path. И там же открывайте сразу новый по новому имени. А внутри функции записи оставьте собственно только запись. 2. Уберите строчку «rn[file_path]:flush()», это тяжёлая операция, на которой у вас всё будет тормозить. Этот flush делайте только перед самым закрытием файла, то-есть перед close(). 3. Зачем вам вторая таблица file_open где вы ставите true, она просто дублирует вашу основную таблицу rn с дескрипторами. Уберите её из кода, а открытие файла для конкретного file_path проверяйте условием «nil == rn[file_path]», а после закрытия файла обнуляйте этот же элемент через «rn[file_path] = nil». 4. Выражение «#rn>files_qty» не сработает, потому что у вас таблица строится по строковым ключам, а оператор # работает только для индексированных по номерам таблиц, то-есть когда они используются как массивы. 5. Структура кода у вас неправильная, запись в файл нужно делать после проверки на nil возврата функции io.open. Вы эту проверку вообще не делаете после вызова io.open, а делает только при повторном вызове основной функции при следующей записи. У вас там нужно часть строк стереть, а часть местами поменять, чтобы привести код в порядок.
Suntor если я уберу flush при каждой записи, не появятся ли чрезмерные риски того, что какая-то часть данных не запишется? Ну например я принудительно остановил скрипт. Ведь в этом случае какие-то строчки потеряются? Или не потеряются?
Let_it_go написал: Suntor если я уберу flush при каждой записи, не появятся ли чрезмерные риски того, что какая-то часть данных не запишется? Ну например я принудительно остановил скрипт. Ведь в этом случае какие-то строчки потеряются? Или не потеряются?
При останове скрипта луа машина, встроенная в терминал, автоматически закрывает все файлы посредством close(). Это происходит с версии qlua 6.xx вроде.
Вызов close() всегда подразумевает flush() - так устроена библиотека С.
Поэтому вы ничем не рискуете.
flush() имеет смысл только в том случае, если вы в реальном времени другой программой читаете создаваемый файл. Flush() сбрасывает файловый буфер на диск немедленно. Без него файловые операции кешируются в памяти. В момент закртытия файла все буферы сбрасываются на диск.
Спасибо, друзья. Проясняется, хотя мне очень тяжело с этим разбираться. Не то образование... Вот текущая редакция функции, которая пишет слепки стакана. Триместр сменился, если путь поменялся. В этом случае закрываем старый файл, открываем новый.
Let_it_go написал: Спасибо, друзья. Проясняется, хотя мне очень тяжело с этим разбираться. Не то образование... Вот текущая редакция функции, которая пишет слепки стакана. Триместр сменился, если путь поменялся. В этом случае закрываем старый файл, открываем новый.
В таком виде, как правильно написал s_mike@rambler.ru, flush перед самым close смысла особого не имеет. Поэтому можете стереть там строчку. Мне вообще ваш подход не нравится. Вы пытаетесь запихать в одну функцию всю логику работы с файлами. Поэтому у вас в этой функции будет куча лишних проверок замедляющий её основную работу — запись. Но даже, в рамках вашего подхода, я бы всё переписал по-другому. Как-то вот так:
Код
rn = rn or {}
rn[paper] = rn[paper] or {}
if file_path~=rn[paper].file_path then
if rn[paper].handler then
rn[paper].handler:close()
end
rn[paper].handler:io.open(file_path, "a+")
if rn[paper].handler then
rn[paper].file_path = file_path
else
mm("QL:open file error "..file_path)
end
end
if rn[paper].handler then
rn[paper].handler:write(value.."\n")
end
— код не проверял, пишу из головы, чтобы передать суть.
Выключил flush. Почему-то на всех сегодняшних файлах стал появляться одинаковый глюк: вот такое искажение:
неадекватная (неполная строчка). Плюс пропуск нескольких секунд. До ошибки время 184444, после ошибки 184449. Может быть я в это время его включал-выключал, но я увы не помню этот момент. Днём на 1 из файлов было то же самое. Раньше, когда flush работал, такого не было. Видоизменил функцию. Добавил в неё flush 1 раз в 100 записей по данной бумаге:
Код
count[paper]=(count[paper] or 0)+1
if count[paper]==100 then
rn[paper].handler:flush()
count[paper]=0
end
Let_it_go написал: Получаю данные колбеком OnParam. В него вставлена обсуждаемая функция.
А внутри OnParam вы несколько раз getParamEx дёргаете для разных параметров? И потом их объединяете в таблицу или строку и кидаете дальше в вашу функцию записи?... если так, то сдаётся мне вы оба (вы и ваш коллега с соседней темы «Некоторые глюки в 7.2») встретились, собратья по несчастью... с одной и той же проблемой...
Покажите, что вы делаете в OnParam, и как у вас идёт вызов вашей функции rec_big_data...
Suntor, эта проблема появилась только сейчас, когда я перестал делать flush на каждой записи. До этого я несколько недель подряд записывал каждый день без перерыва и такой проблемы не было. Она абсолютно новая. Вызываю я функцию так:
При таком вызове рваться не должно... у вас какая-то серьёзная проблема с вводом/выводом. Возможно дело даже не в Lua, а в вашей виртуальной машине, настройках виртуального диска и пр.
Попробуйте отключиться кэш совсем, через file:setvbuf:
Код
function rec_big_data(file_path, value, paper)
rn = rn or {}
rn[paper] = rn[paper] or {}
if file_path~=rn[paper].file_path then
if rn[paper].handler then
rn[paper].handler:close()
end
rn[paper].handler = io.open(file_path, "a+")
if rn[paper].handler then
rn[paper].handler:setvbuf("no") --<<<--- отключение кэша
rn[paper].file_path = file_path
else
mm("QL:open file error "..file_path)
end
end
if rn[paper].handler then
rn[paper].handler:write(value.."\n")
end
end
а в другой день, наоборот, увеличьте его до 1 МиБ, заодно сравните скорость работы, и посмотрите, будут ли глюки и при каком режиме кэширования: