Обновление стакана во время обработки предыдущего обновления - как отработает?


Обновление стакана во время обработки предыдущего обновления - как отработает?
Atom Ответить
15.05.2012


Запущен экспорт стакана по DDE, настроен обработчик событий обновления стакана. Предположим, что активность торгов очень высокая, и очередное событие обновления стакана возникает ещё до того, как завершилась обработка предыдущего события.

Вопрос: что будет происходить в этом случае? Будет накапливаться очередь событий? Новые события будут игнорироваться до тех пор, пока не завершится обработка предыдущего события?

Пока только осваиваю, так что не пинайте, если очевтдные вещи спрашиваю. :)

Теги:


Спасибо:




14 Ответов
Serg

Фотография
Дата: 15.05.2012
Ответить


Algonavt Перейти
Запущен экспорт стакана ...

Я использую вот такую кострукцию, ктото давно посоветовал спасибо ему за это:
Код
int inUse = Interlocked.CompareExchange(ref _inUse, 1, 0);
if (inUse == 0)
{
   try
   {
      // тут наша обработка
   }
   catch (Exception onprE)
   {
      AddLog(StrategyErrorStates.Error, onprE.Message, this);
   }
   finally
   {
      Interlocked.Exchange(ref _inUse, 0);
   }
}
Спасибо:

Algonavt

Фотография
Дата: 15.05.2012
Ответить


Ок, спасибо. Хорошая конструкция. Насколько я понимаю из MSDN-овской матчасти о многопоточности, такая конструкция (оформление "чувствительной" части кода в Interlocked) позволяет застраховаться от того, что новый вызов обработчика случится до завершения предыдущего вызова и что часть кода, выполняющая обработку, будет прервана где-то в середине. Верно ли я понимаю, что пока выполняется код в части "// тут наша обработка", все вызовы того же самого обработчика становятся в очередь?

И ещё вопрос. "Замораживается" ли в случае использования такой конструкции содержимое стакана на время выполнения секции " // тут наша обработка"? Я имею в виду, что если в этой секции будет несколько обращений к содержимому стакана (к примеру, получение массива Bid -> выполнение расчетов с массивом Bid -> получение массива Ask -> выполнение расчетов с массивом Ask), есть ли риск того, что между шагами "получение массива Bid" и "получение массива Ask" содержимое стакана изменится?
Автор топика
Спасибо:

Serg

Фотография
Дата: 15.05.2012
Ответить


Algonavt Перейти
Верно ли я понимаю, что пока выполняется код в части "// тут наша обработка", все вызовы того же самого обработчика становятся в очередь?

Нет они все проходят мимо так как _inUse у нас теперь равен 1 и (inUse == 0) возвращает false

Algonavt Перейти
И ещё вопрос. "Замораживается" ли в случае использования такой конструкции содержимое стакана на время выполнения секции " // тут наша обработка"? Я имею в виду, что если в этой секции будет несколько обращений к содержимому стакана (к примеру, получение массива Bid -> выполнение расчетов с массивом Bid -> получение массива Ask -> выполнение расчетов с массивом Ask), есть ли риск того, что между шагами "получение массива Bid" и "получение массива Ask" содержимое стакана изменится?

Стакан не замораживается. Насколько я знаю он обновляется в отдельном потоке. И чаще всего вы работаете с его копией делая
Код
var md = Trader.GetMarketDepth(seccode);
то есть работаете уже с md. Но тут уже только мои догадки и более точно сможет ответить Михаил или Александр.
Если дважды вызвать приведенный выше код в "// тут наша обработка" то думаю вероятность есть что первый слепок стакана не будет соответствовать второму.
Спасибо:

ra81

Фотография
Дата: 16.05.2012
Ответить


Стакан работает не в потоке main вашей программы. Отсюда если ваша программа подвязывается на события обновления стакана то код выполняемый по событию будет тоже в том же потоке что и стакан. Отсюда если вы этот поток задержите, то и приход нового стакана задержится. А код с interlocked по факту задерживает поток стакана. Отсюда сама конструкция не думаю что функциональна вовсе.

Опять же нужно учесть разные устройства коннекторов, но я уверен что каждый новый стакан не приходит в отдельном новом потоке :). Отсюда таки конструкция бесполезна.
Спасибо:

Serg

Фотография
Дата: 16.05.2012
Ответить


ra81 Перейти
Стакан работает не в потоке main вашей программы. Отсюда если ваша программа подвязывается на события обновления стакана то код выполняемый по событию будет тоже в том же потоке что и стакан. Отсюда если вы этот поток задержите, то и приход нового стакана задержится. А код с interlocked по факту задерживает поток стакана. Отсюда сама конструкция не думаю что функциональна вовсе.

Опять же нужно учесть разные устройства коннекторов, но я уверен что каждый новый стакан не приходит в отдельном новом потоке :). Отсюда таки конструкция бесполезна.

Спасибо за ваше мнение заставили меня задуматься)
А как можно всю эту теорию проверить?
Спасибо:

ra81

Фотография
Дата: 16.05.2012
Ответить


Serg Перейти
ra81 Перейти
Стакан работает не в потоке main вашей программы. Отсюда если ваша программа подвязывается на события обновления стакана то код выполняемый по событию будет тоже в том же потоке что и стакан. Отсюда если вы этот поток задержите, то и приход нового стакана задержится. А код с interlocked по факту задерживает поток стакана. Отсюда сама конструкция не думаю что функциональна вовсе.

Опять же нужно учесть разные устройства коннекторов, но я уверен что каждый новый стакан не приходит в отдельном новом потоке :). Отсюда таки конструкция бесполезна.

Спасибо за ваше мнение заставили меня задуматься)
А как можно всю эту теорию проверить?


Проверить легко. В теле обработки стакана поставить Thread.Sleep(100000) и на входе в функцию поставить Debug.WriteLine("Получил стакан.") перед проверкой if (inUse == 0)

Если будете видеть постоянно новые записи значит стакан приходит без задежек. Если будет пауза значит стакан блочится в теле вашей функции.
Спасибо:

Serg

Фотография
Дата: 16.05.2012
Ответить


Если метод который вы мне предложили верен, то все ок. Блокировки нет. Стакан обновляется в отдельном потоке)
Спасибо:

ra81

Фотография
Дата: 16.05.2012
Ответить


Serg Перейти
Если метод который вы мне предложили верен, то все ок. Блокировки нет. Стакан обновляется в отдельном потоке)

Ну а реализацию приложите метода с проверкой.... А то странно. Возможно это квиковская особенность.
Спасибо:

Serg

Фотография
Дата: 16.05.2012
Ответить


ок выложу
Спасибо:

Maxim

Фотография
Дата: 16.05.2012
Ответить


Serg Перейти
Algonavt Перейти
Запущен экспорт стакана ...

Я использую вот такую кострукцию, ктото давно посоветовал спасибо ему за это:
Код
int inUse = Interlocked.CompareExchange(ref _inUse, 1, 0);
if (inUse == 0)
{
   try
   {
      // тут наша обработка
   }
   catch (Exception onprE)
   {
      AddLog(StrategyErrorStates.Error, onprE.Message, this);
   }
   finally
   {
      Interlocked.Exchange(ref _inUse, 0);
   }
}



Я обычно такой конструкцией пользуюсь.


Код

if (Monitor.TryEnter(lockObject) == true)
{
	try
	{
		// Код, который необходимо выполнить только в одном потоке одновременно
	}
	finally
	{
		Monitor.Exit(lockObject);
	}
}
else
{
	 // Если  у нас не получилось блокировать       
}   

Спасибо:

Algonavt

Фотография
Дата: 23.05.2012
Ответить


ra81 Перейти
Serg Перейти
ra81 Перейти
Стакан работает не в потоке main вашей программы. Отсюда если ваша программа подвязывается на события обновления стакана то код выполняемый по событию будет тоже в том же потоке что и стакан. Отсюда если вы этот поток задержите, то и приход нового стакана задержится. А код с interlocked по факту задерживает поток стакана. Отсюда сама конструкция не думаю что функциональна вовсе.

Опять же нужно учесть разные устройства коннекторов, но я уверен что каждый новый стакан не приходит в отдельном новом потоке :). Отсюда таки конструкция бесполезна.

Спасибо за ваше мнение заставили меня задуматься)
А как можно всю эту теорию проверить?


Проверить легко. В теле обработки стакана поставить Thread.Sleep(100000) и на входе в функцию поставить Debug.WriteLine("Получил стакан.") перед проверкой if (inUse == 0)

Если будете видеть постоянно новые записи значит стакан приходит без задежек. Если будет пауза значит стакан блочится в теле вашей функции.

Сделал следующий код:
Код

trader.QuotesChanged += depths =>
			{
				if (!stakanStarted)
				{
					if (_security != null)
					{
						_depth = depths.FirstOrDefault(d => d.Security == _security);
						
						if (_depth != null)
						{
							Console.WriteLine("Стакан для {0} появился.", _security.Code);
							stakanStarted = true;
							if (_portfolio != null && _security != null)
								waitHandle.Set();
						}
					}
				}
				// Обработка стаканов после запуска экспорта
				else
				{
					int inUse = Interlocked.CompareExchange(ref _inUse, 1, 0);
					Console.WriteLine("Стакан обновился!");
					if (inUse == 0)
					{
						try
						{
							Thread.Sleep(100000);
							var _bid = _depth.Security.BestBid.Price;
							var _ask = _depth.Security.BestAsk.Price;
							
							if (_bid != lastBid)
							{
								lastBid = _bid;
								updateRequired = true;
							}
							
							if (_ask != lastAsk)
							{
								lastAsk = _ask;
								updateRequired = true;
							}
							
							if (updateRequired)
							{
								updateRequired = false;
								currentTime = DateTime.Now.ToString("HH:mm:ss.fff");
								Console.WriteLine("Time: {0} : Best Bid = {1}, Best Ask = {2}", currentTime, lastBid, lastAsk);
							}
						}
						catch (Exception onprE)
						{
							Console.WriteLine("Exception: " + onprE.ToString());
							// AddLog(StrategyErrorStates.Error, onprE.Message, this);
						}
						finally
						{
							Interlocked.Exchange(ref _inUse, 0);
						}
					}
				}
			};

Результат: сообщения "Стакан обновился" и форматированный вывод лучшей пары появляются на консоли раз в сто секунд.

В квике вижу, что спред прыгает, а в робота ничего не поступает. Вывод: блочится, выходит, экспорт стакана...
Автор топика
Спасибо:

Serg

Фотография
Дата: 28.05.2012
Ответить


А откуда вы подписываетесь на событие trader.QuotesChanged?
Спасибо:

Algonavt

Фотография
Дата: 30.05.2012
Ответить


Serg Перейти
А откуда вы подписываетесь на событие trader.QuotesChanged?

Для простоты (пока экспериментирую) всё действие происходит в main - точно так же, как в примере из стандартной поставки.
Автор топика
Спасибо:

Serg

Фотография
Дата: 30.05.2012
Ответить


Algonavt Перейти
Serg Перейти
А откуда вы подписываетесь на событие trader.QuotesChanged?

Для простоты (пока экспериментирую) всё действие происходит в main - точно так же, как в примере из стандартной поставки.

Тоесть это не внутри стратегии. Если так то параллельно работать не будет.
Спасибо:


Добавить файлы через драг-н-дроп, , или вставить из буфера обмена.

loading
clippy