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 строку.
  
			
			
			
			
		
 
				 | 
			
			
				| 
					
				 | 
				
					
	
		| 
			Спасибо:
		 | 
		
		
			 
		 | 
	 
 
				 | 
			
			
				| 
					
				 |