Mikhail Sukhov
|
Дата: 11.08.2010
Можете сделать проще. Отнаследоваться от QuikTrader, переопределить
ReStartExport и там прописать свою логику проверки - нужно
перезапускать экспорт или не нужно.
|
|
|
|
Спасибо:
|
|
|
|
|
|
Иванов Андрей
|
Дата: 12.08.2010
|
|
|
|
|
Комментарий о чём? ;) У вас синтетический случай, поэтому такой
огромный прирост.
Если вопрос "почему?", то потому что когда пишете сразу в файл,
копирование в памяти всего одно, а когда у вас несколько раз
осуществляется операция конкатенации, вы копируете данные много раз.
Из неочевидного строки создаются на хипе, а не на стеке, их создаётся
много и GC освобождает занимаемую ими память. В случае 2 выделения/
освобождения памяти практически нет, все данные в кэше процессора,
поэтому он работает на максимальной скорости, а не спотыкается об
ожидание данных из медленной памяти.
Ну а запись в файл, как вы уже заметили, происходит очень быстро =)
Потому что вывод буферизованный -- когда вы делаете 5 вызовов вместо
одного, они все пишут в один буфер и оверхеада по сравнению с записью
всей строки одним вызовом почти нет.
Если будете увлекаться файлами, столкнётесь с ещё одной неочевидной
штукой. Называется IOPS. Пока читаете/пишете линейно, скорости
обычного SATA будет достаточно -- придумана куча технологий для
ускорения линейного доступа (кэши, буферы, группировка вызовов
операционной системой, NCQ), но как только чтение станет случайным,
пиковые 400-500 IOPS SAS-диска за тысячу долларов покажутся жалкой
пародией на скорость =) Потому что в переводе на мегабайты получится
чуть больше 10 мегабайтов в секунду, это в 10-15 раз меньше
современного бытового SATA-диска на линейном доступе.
|
|
|
|
Спасибо:
|
|
|
|
|
|
Mikhail Sukhov
|
Дата: 12.08.2010
В том то и дело, что я устанавливаю AutoFlush = true. А это отключает
всякую буферизацию. А если бы был буфер, я правильно понимаю, что
сброс буфера в файл происходит асинхронно?
Насчет хипа - я так и думал. string - это ведь класс. Но ведь буферы у
StreamWriter наверняка хранят не массив object, а массивы byte[].
Последние - это перевод переданных строк в файловой представление. Так
вот, а массивы так же хранятся в хипе, и так же нужно время на перевод
из строки в byte[]. Где же тогда экономия?
Про рандом и последовательный доступ понятно. Я читал об этом раньше.
Надеюсь в S# не придется с этим столкнутся. Не хотелось бы погрязнуть
в системных тонкостях =)
|
|
|
|
Спасибо:
|
|
|
|
|
|
Иванов Андрей
|
Дата: 13.08.2010
|
|
|
|
|
AutoFlush занимается тем, что сбрасывает буферы самого StreamWriter в
подлежащий стрим. Использование этого флага с файлами ничего не
меняет. Писать можно без буферов, потому что под StreamWriter должен
быть какой-то FileStream, который сам будет буферизовать вывод, плюс
есть буфер ядра.
Выключить буферизацию в ядре можно только ключом в реестре на всю
систему или открывая файл. Отключить буфер после открытия файла, по-
моему, невозможно -- необходимость буферизации известна до
использования файла. По умолчанию буфер ядра в Windows Server
несколько мегабайтов, сколько он в десктопах, не знаю. В десктопах и
серверах разные схемы кэширования и буферов по умолчанию, в серверах
сейчас (2008/2008R2) кэширование по умолчанию может съесть всю память
и программам придётся свапиться =)
Сброс буфера ядра асинхронный. Сбросы прикладных буферов синхронные.
Массивы буферов не создаются и не удаляются 100 тысяч раз в секунду =)
Они один раз создаются и живут какое-то продолжительное время.
Когда вы делаете s1 += s2;, вы создаёте один объект (результат
конкатенации s1 и s2) и отдаёте GC один объект (тот, на который до
операции указывал s1). В случае с буферами все остаются при своих,
происходит только одно копирование. Самый шик, когда строка не
помещается в Gen 0 и отправляется в LOH -- в этом случае основную
часть процессорного времени занимает удаление объектов =) Но это не
наш случай, потому что строка должна быть больше 40 тысяч обычных
символов (а необычных, типа индийских, ещё на треть меньше).
|
|
|
|
Спасибо:
|
|
|
|
|
|
Alexander
|
Дата: 15.08.2010
т.е. перезапускать экспорт только в том случае, если нет подключения:
public class OwnQuikTrader : QuikTrader
{
public OwnQuikTrader(string path, string ddeServer, string
dllName) :
base(path, ddeServer, dllName)
public override void ReStartExport()
{
if (!IsConnected)
base.ReStartExport();
}
}
?
|
|
|
|
Спасибо:
|
|
|
|
|
|
Mikhail Sukhov
|
Дата: 16.08.2010
Да, так, если такого поведения достаточно.
|
|
|
|
Спасибо:
|
|
|
|
|
|
Mikhail Sukhov
|
Дата: 16.08.2010
Массив буферов создается один раз, согласен (возможно еще как-то
увеличивается уменьшается, но это не так важно). Но сами то буферы
нет. Они создаются так же часто, как мы вызываем Write. string в
byte[] - создаем, int в byte[] - создаем, DateTime в byte[] -
создаем... Тоесть, в любом случаем необходимо произвести конфертацию,
а это создание массива байтов.
Копирование byte[] в массив буферов?
|
|
|
|
Спасибо:
|
|
|
|
|
|
Иванов Андрей
|
Дата: 17.08.2010
|
|
|
|
|
Не, массивы байтов не создаются, создаются строки. Много-много строк
(иногда char[]).
Для начала форматная строка парсится (это TextWriter.Write).
public virtual void Write(string format, object arg0, object arg1)
{
this.Write(string.Format(this.FormatProvider, format, new object[]
{ arg0, arg1 }));
Из-за того, что выделенной памяти не хватило на создание конечной
строки (размер форматной + 16 символов), происходит реаллок с
выделением памяти в два раза больше и копированием. При парсинге
форматной строки аллоки поменьше для внутреннего использования.
Копирований, соответственно, пачка.
Тут основная часть CPU и съедается.
Я писал сделки в файлы инструментов и каждый раз (запись сделки)
считал путь к имени файла инструмента. Кэширование этой операции дало
примерно пятикратный прирост скорости записи. Закэшировал остальные
операции вычисления пути (тоже просто конкатенации и Path.Combine),
прирост ещё раза в два.
Форматная строка вида
string dealStr =
string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0};
{1:T};{2};{3};{4};{5}", _id, _timeStamp, _price, _count, _volume,
_operation.HasValue ? _operation.ToString() : "0");
по скорости почти идентична просто конкатенации или StringBuilder.
Предположу, что здесь хватило выделенного начального буфера (40
символов) и форматтер InvariantCulture работает быстрее
CurrentCulture. Выяснять лениво, мне достаточно того, что так писать
красивее, чем через + и работает некритично медленнее.
Писать напрямую в файл не стал, потому что после включения кэширования
путей время полного копирования сделок за сутки составляет секунд 10.
А если вместо форматной строки выше писать константу такой же длины,
скорость пару секунд. 2 секунды или 10, роли не играет.
|
|
|
|
Спасибо:
|
|
|
|
|
|
Alexander
|
Дата: 23.08.2010
|
|
|
|
|
Опять проблема возникла с запуском нескольких стратегий на нескольких
квиках.
Сейчас на сервере запущено 7 квиков и суммарно должно было бы
запуститься 13 стратегий.
Я запускаю следующим образом:
//цикл по всем стратегиям
//для каждой из стратегий получаю список из счетов для которых данная
стратегия не была запущена
TimeFrameStrategy tfStrategy = null;
//в зависимости от стратегии tfStrategy инициализирую конструктором
нужного класса (наследуемого как раз от TimeFrameStrategy)
//регистрирую ТФ
tfStrategy.Log += Strategy_OnLog;
var newDateTimeDir = string.Format("Logs\{0}{1:00}{2:00}",
DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
if (!Directory.Exists(newDateTimeDir))
{
Directory.CreateDirectory(newDateTimeDir);
var logger = new StrategyLogger("{0}\_{1}
_{2}.txt".Put(newDateTimeDir,
Enum.GetValues(typeof (StrategiesName)).GetValue(i),
account.Account));
logger.Strategies.Add(tfStrategy);
_strategyManager.Register(tfStrategy, port, riFut); // где port -
портфель нужный, riFut - фьюч из Securities. и то и то не null
tfStrategy.Start();
В результате у меня для всех 13 стратегий создаются логи, но работают
не все (в разные запуски разное число, от 4 до 8 было) - в логе
неработающих стратегий лишь строчка
11:06:42.8281250 Volume_1_01:00:05 Volume_1 запущена.
и ничего более, хотя при каждом вызове OnProcess в лог должно что-то
писаться.
Вот сейчас в 8 стратегиях из 13 пишется, в 5 - лишь 1 эта строчка.
С чем это связано?
|
|
|
|
Спасибо:
|
|
|
|
|
|
Alexander
|
Дата: 23.08.2010
Попробовал запускать стратегии после того, как добавил их в
StrategyManager - не помогло, последние 5 из добавленных стратегий всё
равно не работают - в лог пишут лишь 1 строку.
|
|
|
|
Спасибо:
|
|
|
|
|