Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Как идет обработка одновременных событий?


Автор: dAlex 21.2.2011, 14:06
Проблема такая. У меня есть биржевой робот, который, грубо говоря, реагирует на событие "произошла сделка" и далее есть функция обработки. В зависимости от того, какая была сделка, следующая сделка может обрабатываться по-разному. Но иногда бывает так,  что одновременно происходят 2 сделки. Что происходит в таком случае с их обработкой? возникает ли какая-то очередь событий? Или обработка двух событий происходит одновременно в разных потоках?

Автор: Экскалупатор 21.2.2011, 14:22
а как робот узнает о том что сделка произошла? вообще "одновременность" этого вопроса очень  сомнительна. есди предположить что твой робот многопоточный, и он работает с многопоточной системой, которая ему в нескольких потоках одновременно сообщает о том что что то произошло, то в таком случае обработка должна идти параллельно. но если робот слушает сеть, то ему не может прийти два сообщения одновременно. сначала придет один пакет потом другой.(т.е. очередь будет), а дальше зависит от робота(как он реализован так и будет обрабатывать, ждать или запускать второй поток).

Добавлено через 7 минут и 19 секунд
Цитата(dAlex @  21.2.2011,  13:06 Найти цитируемый пост)
Или обработка двух событий происходит одновременно в разных потоках?

и вообще если робот твой, то ты должен знать как у тебя происходит обработка событий. если параллельность не реализована изначально то события могут просто игнорироваться пока приложение занято какой то работой.

Автор: dAlex 21.2.2011, 14:42
робот узнает по ссылке из DDE. не знаю, как оно там =)
робот-то мой, обработка событий происходит просто "подпиской" на событие, такого плана
Код

MainWindow.Instance.Trader.NewMyTrades += OnNewMyTrades;

просто для меня и так было открытием узнать, что нельзя выводить данные одновременно с отрисовкой интерфейса, и что в таком случае надо делать BeginInvoke. Возможно, тут еще что-то такое

upd: в функции обработки у меня пишется лог в файл. Добавила там первой строчкой запись строки типа "идет обработка сделки такой-то". Сейчас наблюдаю в логе 2 таких строчки подряд, то есть как-то одновременно обработка 2х сделок-событий происходит  smile

Добавлено @ 14:50
вот блин! сама уже не разбираюсь в своем коде. Вот так идет обработка сделок

Код

public void OnNewMyTrades(IEnumerable<MyTrade> myTrades)
        {
            foreach (var myTrade in myTrades)
            {
                var trade = myTrade.Trade;   
                MainWindow.Instance.Dispatcher.BeginInvoke(new AddDataByNewTradeDelegate(AddDataByNewTrade), myTrade);                   
            }
        }


AddDataByNewTrade и есть функция обработки сделки

то есть это и есть разные потоки? или как?

Автор: -Mikle- 21.2.2011, 15:11
Ну видимо одновременно все таки... Ставьте lock на выполнение кода в событии или что-нить подобное для синхронизации потоков.

А вообще, если к вам приходит что-то в многопоточном режиме, то надо либо быть уверенным что интервал между посылками (в среднем) будет достаточный для того чтоб код отработал, либо надо тогда уже придерживаться многопоточной среды до конца.
Например: идут асинхронные посылки с средним интервалом 100мс (в среднем имеется ввиду что могут например прийти две посылки одновременно, а потом до следующей например пройдет 200мс). Если код обработки посылок (ЗАВЕДОМО(!)) выполняется не более 50-70мс, то можно ставить тогда все эти посылки в очередь на выполнение в одном потоке. Если нет, то однозначно будет образовываться очередь, которая приведет в итоге к краху приложения. В последнем случае, надо очень быстро ложить посылки в очередь и отпускать блокировку сразу после этого. А далее, разгребать эту очередь используя пул потоков. Если сообщение на вершине очереди лежит например 1 сек, то пулер должен натравить еще один поток на эту же самую очередь. И наоборот, если поток в пулуре простаивает в течение какого-то периода, то надо убить поток сэкономив тем самым ресурсы процессора.

Автор: dAlex 21.2.2011, 15:27
Цитата(-Mikle- @  21.2.2011,  15:11 Найти цитируемый пост)
Ставьте lock на выполнение кода в событии или что-нить подобное для синхронизации потоков

а как это делается? 

Автор: -Mikle- 21.2.2011, 18:17
Код

lock(...syncObject...)
{
    ...........
    // блокируемый код
    ...........
}


До тех пор пока выполняется код внутри lock ни один другой поток не зайдет внутрь. Они все будут стоять в очереди (схематично можно считать, что все они будут стоять на строчке lock). Как только выполнение кода завершится одним потоком, другой (один) поток войдет внутрь, остальные будут продолжать стоять. Имейте ввиду, что очередь в данном смысле, не означает соблюдение очередности пришедших потоков. Например, потоки могут прийти в порядке 1,2,3,4, но выполнятся могут в порядке 1,4,3,2. В данном случае, этот порядок не контролируем и в большинстве случаев, нет необходимости его как-либо контролировать. Подробнее про все это можно найти на MSDN и просторах интернета.

PS: Помните, что вы не обязаны блокировать весь метод целиком. Вы можете заблокировать только часть кода.
PPS: Про синхронизацию потоков это еще не все, существует целая масса средств для многопоточных приложений, позволяющих выполнять потоковую синхронизацию, мониторинг, ограничения и прочие связанные вещи.

Автор: dAlex 22.2.2011, 10:48
-Mikle-, спасибо =) читаю в мсдне сейчас про это. Но не знаю, какой мне объект указывать для блокировки?

Автор: -Mikle- 22.2.2011, 13:29
Вообще любой, но обычно на практике для каждого блокируемого кода создают просто обжект. Имеется ввиду для каджого логически блокируемого кода. Предположим, у вас есть тре метода, которые производят какие-то операции с одной коллекцией и необходимо, чтобы имелся многопоточный доступ к этим трем методам. В этом случае, объект блокировки для всех частей кода который работает с коллекцией будет один. Можно использовать саму коллекцию в качестве инстанса блокировки, но как я уже сказал, лучше создать отдельный экземпляр класса object, например так:

Код

private object personListSyncObj = new object();
....
public void AddPerson()
{
    lock(personListSyncObj)
    {
        // do anything with your person list
    }
}

public void DeletePerson()
{
    lock(personListSyncObj)
    {
        // do anything with your person list
    }
}

public void SortPersonList()
{
    lock(personListSyncObj)
    {
        // do anything with your person list
    }
}

Автор: dAlex 22.2.2011, 15:48
-Mikle-, сделала так, как вы сказали =) на первый взгляд вроде правильно работает, даже отрисовка интерфейса притормаживает, когда обработка идет, но надо еще тестить.

Автор: Экскалупатор 22.2.2011, 16:25
Цитата(dAlex @  22.2.2011,  14:48 Найти цитируемый пост)
даже отрисовка интерфейса притормаживает

а почему притормаживает? у тебя же все в отдельном потоке работает.

Автор: -Mikle- 22.2.2011, 17:57
Цитата(Экскалупатор @  22.2.2011,  19:25 Найти цитируемый пост)
а почему притормаживает? у тебя же все в отдельном потоке работает. 


Я полагаю, что dAlex весь код обработки посылки охватила методом Invoke. dAlex, если я прав, то необходимо исправить это, охватив методом Invoke только те части кода, которые непосредственно обновляют окно. Иначе, пропадает какой либо смысл в многопоточности, так как отдельный поток в таком случае, просто передает всю работу основному потоку, а сам просто сидит на паузе и ждет завершения. Если будут проблемы с этим, создавайте отдельную тему и если не я, то кто-то еще вам обязательно помогут. Удачи вам в освоении асинхронных взаимоотношений  smile

Добавлено через 2 минуты и 54 секунды
А вообще, стремление должно быть к тому, чтоб максимально возможно избегать обновления интерфейса из другого потока (насколько это возможно и насколько это позволит дотошный пользователь вашего приложения smile )

Автор: dAlex 24.2.2011, 10:22
-Mikle-, так смысл как раз в том, чтобы одновременно коллекции данных менял только один поток =) а как раз при обновлении коллекций обновляется окно, они забиндены с листбоксами =)

Добавлено через 1 минуту и 19 секунд
а пользователю пофигу, лишь бы правильно работало, да побыстрее  smile не виноватая я, что приходится такие извращения городить, это все как раз по требованиям пользователя и происходит =)

Добавлено через 13 минут и 40 секунд
хотя нет, вот сейчас по логу снова проскочило две одновременных обработки - или не стоит судить по логу? лог пишется участками, но внутри lock

Автор: dAlex 24.2.2011, 12:37
или все-таки это не одновременная обработка, а происходит выход из функции в самом начале, из-за одной штуки, надо проверить...

Автор: dAlex 24.2.2011, 13:46
там, оказывается, иногда эксепшн вылезал, так что это не одновременная обработка была, а просто быстрый выход из нее =)
значит, работает =) спасибо всем за помощь =)

Добавлено через 2 минуты и 15 секунд
Цитата(-Mikle- @ 22.2.2011,  17:57)
Удачи вам в освоении асинхронных взаимоотношений  smile

Ох, спасибо =) вот так всегда, по закону подлости - что-то совершенно новое и довольно объемное попадается именно тогда, когда нет времени это нормально рассмотреть и реализовать =)

Автор: -Mikle- 24.2.2011, 21:31
Цитата(dAlex @  24.2.2011,  16:46 Найти цитируемый пост)
именно тогда, когда нет времени это нормально рассмотреть и реализовать

Это обычное дело для многих я думаю, я к таким вещам уже привык smile Еще раз удачи и заходите к нам smile

Автор: dAlex 24.2.2011, 22:19
-Mikle-, обязательно =) я и не ухожу  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)