VassilSanych
|
Дата: 01.02.2013
|
|
|
|
|
MenDel:
может это этот сервер (time.nist.gov:123) не айс,
Это ссылка на рандомный сервер из списка.
Да, временами он govnist.
Вот мой код синхронизации:
private int _timeSyncCount = 0;
private void SyncTime()
{
try
{
CustomSyncTime();
}
catch (Exception)
{
this.AddErrorLog("Ошибка синхронизации времени");
ThreadPool.QueueUserWorkItem(_ => RecurciveSyncTime());
}
}
private void CustomSyncTime()
{
// уже синхронизировалось
if (LoggingHelper.NowOffset != TimeSpan.Zero)
return;
LoggingHelper.NowOffset = new NtpClient("time.nist.gov:123").GetLocalTime(TimeZoneInfo.Local, 10000).Subtract(DateTime.Now);
this.AddDebugLog("Время синхронизировано");
}
private void RecurciveSyncTime()
{
try
{
CustomSyncTime();
return;
}
catch
{
this.AddErrorLog("Ошибка синхронизации времени");
}
// первая треть попыток - раз в 10 секунд
if (++_timeSyncCount < Settings.Default.TimeSyncAttempts / 3)
{
Thread.Sleep(10000);
RecurciveSyncTime();
}
// вторая треть попыток - раз в 100 секунд (чуть больше полутора минут)
else if (_timeSyncCount < 2 * Settings.Default.TimeSyncAttempts / 3)
{
Thread.Sleep(100000);
RecurciveSyncTime();
}
// оставшиеся попытки - раз в 1000 секунд (16.7 минут)
else if (_timeSyncCount < Settings.Default.TimeSyncAttempts)
{
Thread.Sleep(1000000);
RecurciveSyncTime();
}
}
|
|
|
|
|
|
|
MenDel
|
Дата: 01.02.2013
|
|
|
|
|
Это ссылка на рандомный сервер из списка.
Да, временами он govnist.
Вот мой код синхронизации:
private int _timeSyncCount = 0;
private void SyncTime()
{
try
{
// уже синхронизировалось
if (LoggingHelper.NowOffset != TimeSpan.Zero)
return;
LoggingHelper.NowOffset = new NtpClient("time.nist.gov:123").GetLocalTime(TimeZoneInfo.Local, 10000).Subtract(DateTime.Now);
this.AddDebugLog("Время синхронизировано");
}
catch (Exception)
{
this.AddErrorLog("Ошибка синхронизации времени");
// первая треть попыток - раз в 10 секунд
if (++_timeSyncCount < Settings.Default.TimeSyncAttempts / 3)
ThreadPool.QueueUserWorkItem((x) =>
{
Thread.Sleep(10000);
SyncTime();
});
// вторая треть попыток - раз в 100 секунд (чуть больше полутора минут)
else if (_timeSyncCount < 2 * Settings.Default.TimeSyncAttempts / 3)
ThreadPool.QueueUserWorkItem((x) =>
{
Thread.Sleep(100000);
SyncTime();
});
// оставшиеся попытки - раз в 1000 секунд (16.7 минут)
else if (_timeSyncCount < Settings.Default.TimeSyncAttempts)
ThreadPool.QueueUserWorkItem((x) =>
{
Thread.Sleep(1000000);
SyncTime();
});
}
}
А я ща сделал просто, будет коннектится пока не получит свое, вот
private void TimeSync()
{
try
{
LoggingHelper.SyncMarketTime(50);
this.GuiAsync(() =>
{
Message("Время синхронизировано");
});
}
catch { TimeSync(); }
}
А запускаю его так ```csharp
ThreadPool.QueueUserWorkItem(_ => TimeSync());
А можно тупо поставить прогу Absolute Time Corrector, очень удобная, ставишь интервал и она сама часы на компе подводит, хоть каждую секунду.
|
|
|
|
Спасибо:
|
|
|
|
|
|
VassilSanych
|
Дата: 01.02.2013
MenDel:
А я ща сделал просто, будет коннектится пока не получит свое, вот
Так нельзя.
Во-первых, если опрашивать чаще, чем раз в 4 секунды, то сервер будет блокировать запросы (так написано у них)
во-вторых, если запрашивать в одном потоке, то будет блокироваться основной функционал ради второстепенной информации,
в-третьих, от частых сообщений об ошибке засрётся лог,
upd
в-четвёртых, рекурсия блокирует GC, и при большой рекурсивной вложенности будет переполнение буфера.
upd
Особенно рекурсия через Exception. А там между прочим каждый раз будет производиться сериализация после рефлекшн.
Представляете какого размера будет staсktrace после 20000-й итерации?
|
|
|
|
|
|
|
MenDel
|
Дата: 01.02.2013
|
|
|
|
|
VassilSanych:
MenDel:
А я ща сделал просто, будет коннектится пока не получит свое, вот
Так нельзя.
Во-первых, если опрашивать чаще, чем раз в 4 секунды, то сервер будет блокировать запросы (так написано у них)
во-вторых, если запрашивать в одном потоке, то будет блокироваться основной функционал ради второстепенной информации,
в-третьих, от частых сообщений об ошибке засрётся лог,
upd
в-четвёртых, рекурсия блокирует GC, и при большой рекурсивной вложенности будет переполнение буфера.
upd
Особенно рекурсия через Exception. А там между прочим каждый раз будет производиться сериализация после рефлекшн.
Представляете какого размера будет staсktrace после 20000-й итерации?
Если не считать первой причины,
я использую другой поток,
я не вывожу ошибку в лог,
и ты ведь тоже запускаешь повторно метод из catch, я немного не понимаю про рекурсию и GC
Может проще прописать в LoggingHelper.SyncMarketTime(5000); 5000 или другое кол-во милисекунд?
и тогда не придется усыплять поток и осчитывать итерации и тем более что он сам задает NowOffset.
Или я что то недопонимаю.
|
|
|
|
Спасибо:
|
|
|
|
|
|
VassilSanych
|
Дата: 01.02.2013
|
|
|
|
|
MenDel:
Если не считать первой причины,
я использую другой поток,
каюсь, не обратил внимание на то, что вызов из дополнительного потока.
MenDel:
я не вывожу ошибку в лог,
хммм... довольно опрометчиво.
MenDel:
и ты ведь тоже запускаешь повторно метод из catch, я немного не понимаю про рекурсию и GC
у меня ограниченное количество запусков и большие паузы.
GC не отслеживает переменные метода, пока он не завершён, вроде.
Но в любом случае при глубокой рекурсии будет переполнение стека на одну только адресацию, а отжирание памяти на сериализацию исключений - это будет бонус :)
Не забывай, что в каждом исключении будет нарастающая вложенность.
MenDel:
Может проще прописать в LoggingHelper.SyncMarketTime(5000); 5000 или другое кол-во милисекунд?
на сколько я понимаю, это таймаут, а не пауза
MenDel:
и тогда не придется усыплять поток и осчитывать итерации и тем более что он сам задает NowOffset.
Или я что то недопонимаю.
Ставить дополнительный поток на паузу - вещь не накладная. Главное, чтобы слишком много потоков не занимать, но с пулом это вроде тоже не большая проблема.
В принципе конечно можно всё в одном дополнительном потоке делать. Просто лень было лишний метод писать :)
Идея была в том, что первая попытка выполняется синхронно, а дальше уже в фоне.
Кстати методика себя оправдала.
Запустил - писало, что ошибка синхронизации. Оставил, пошёл ужинать. Через 2 часа обнаружил, что практически все 2 часа синхронизация не срабатывала и сработала только попытки с 18-й (у меня их всего - 21 была).
|
|
|
|
Спасибо:
|
|
|
|
|
|
VassilSanych
|
Дата: 01.02.2013
Замучила совесть: исправил свой код.
Теперь - в одном дополнительном потоке и без вложенных исключений.
Саму синхронизацию выделил в отдельный метод.
Возможно стоит перебрать сервера из списка
http://tf.nist.gov/tf-cgi/servers.cgi
, выбрать вручную несколько хороших и выбирать из их списка, не доверяя стандартному адресу.
Уж больно он нестабильный. Наверное, большинство серверов перманентно в дауне.
|
|
|
|
Спасибо:
|
|
|
|
|
|
aerv
|
Дата: 02.02.2013
Без рекурсии:
void TimeSync(object state) {
int count = 0;
const int maxAttempts = 100;
while (true) {
try {
// Getting time offset
// Logging
break;
} catch {
count++;
// Logging
}
if (count >= maxAttempts)
break;
Thread.Sleep((int) (1000*(3 + Math.Exp(count/5.0)))); // Рассчитывать задержку можно как угодно
}
((ManualResetEvent) state).Set();
}
[TestMethod]
public void TimeCorrectTest() {
var ev = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem( TimeSync, ev );
ev.WaitOne(); // Блокировка - для теста
}
Кстати, для синхронизации времени вполне достаточно настроить штатную службу времени в Windows.
параметры реестра
сервера
пул серверов
Это для общего понимания
|
|
|
|
Спасибо:
|
|
|
|
|
|
VassilSanych
|
Дата: 02.02.2013
aerv:
А зачем рекурсия-то?
Можно и так.
Правда блокировать торговый функционал, пока не будет успешной синхронизации часов, - это, повторюсь, не комильфо.
aerv:
Кстати, для синхронизации времени вполне достаточно настроить штатную службу времени в Windows.
параметры реестра
Там есть небольшая сносочка с предупреждением. По смыслу - "осторожно! мы сами этой хрени не доверяем".
|
|
|
|
Спасибо:
|
|
|
|
|
|
MenDel
|
Дата: 02.02.2013
Да кстати можно ещ добавить проверку инета, а то вдруг его отрубят а он будет все пытвться время узнать.
Так ведь никакой рекурсии не будет?
ThreadPool.QueueUserWorkItem(_ => TimeSync());
private void TimeSync()
{
IPStatus status = IPStatus.Unknown;
try
{
PingReply pr = new Ping().Send(@"google.ru");
status = pr.Status;
}
catch { }
if (status == IPStatus.Success)
{
int i = 0;
while(true)
{
i++;
try
{
LoggingHelper.SyncMarketTime(50);
this.GuiAsync(() => Message("Время синхронизировано"));
break;
}
catch
{
if (i%10 == 0)
{
PingReply pr = new Ping().Send(@"google.ru");
status = pr.Status;
}
if (status != IPStatus.Success) break;
if (i <= 10) Thread.Sleep(1000);
else if (i > 10 && i <= 50) Thread.Sleep(10000);
else if (i > 50) Thread.Sleep(60000);
}
}
}
}
|
|
|
|
Спасибо:
|
|
|
|
|
|
aerv
|
Дата: 03.02.2013
VassilSanych:
aerv:
Кстати, для синхронизации времени вполне достаточно настроить штатную службу времени в Windows.
параметры реестра
Там есть небольшая сносочка с предупреждением. По смыслу - "осторожно! мы сами этой хрени не доверяем".
Ну, у меня много месяцев она работает так как надо. Разумеется, я никому ничего не навязываю. )
MenDel:
Да кстати можно ещ добавить проверку инета, а то вдруг его отрубят а он будет все пытвться время узнать.
Так ведь никакой рекурсии не будет?
А смысл всего этого? Если инет есть, то и по NTP ответ придет. Если инета нет, то и сделать ничего нельзя.
|
|
|
|
Спасибо:
|
|
|
|
|