19 / 19 / 14
Регистрация: 06.08.2009
Сообщений: 533
1

Коллекция была изменена; невозможно выполнить операцию перечисления

12.07.2018, 13:34. Показов 2422. Ответов 10
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Подскажите пожалуйста, почему так происходит.
Выполняю такой код:
C#
1
2
3
4
5
 foreach (Signal signal in signals)
                {
                    //decimal a = signal.price;
                    //обработаем сигнал
                    MoneyManagerCountInfo count_info = await money_manager.get_count(signal, driver);
Выполняю в потоке. В данном цикле нигде не команды изменения самой коллекции.
Но выскакивает сабж.
И, странно, когда я комменчу строку
C#
1
MoneyManagerCountInfo count_info = await money_manager.get_count(signal, driver);
Исключение перестает выскакивать.
А внутри get_count у меня вот что:
C#
1
2
3
4
5
6
        public async Task<MoneyManagerCountInfo> get_count(Signal signal, ITerminalDriver driver)
        {             
 
            decimal lot_size = 1;
            decimal cash = await driver.moneyAvailable();
            return null;
Все вот из-за этой строки:
C#
1
 decimal cash = await driver.moneyAvailable();
Когда ее убираю, все нормально.
но внутри moneyAvailable тоже нет ничего что работало бы с данной коллекцией
Подскажите пожалуйста, как это можно отладить?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
12.07.2018, 13:34
Ответы с готовыми решениями:

Коллекция была изменена; невозможно выполнить операцию перечисления
Здравствуйте, все не могу разобраться, где допустил ошибку. Выполняемый код:

Коллекция была изменена; невозможно выполнить операцию перечисления
foreach (VigruzkaSpecZvan s in massiv._VigruzkaSpecZvan) { ...

Коллекция была изменена; невозможно выполнить операцию перечисления. Как бороться?
Добрый день. Выполняю такой код: public void redraw_grid() { if...

"Коллекция была изменена" - там, где она не была изменена
Непойму что за глюканы творятся... Код: while (sitemapUrls.Count != sitemapUrlsChecks.Count) ...

10
Эксперт .NET
12090 / 8369 / 1280
Регистрация: 21.01.2016
Сообщений: 31,548
12.07.2018, 13:44 2
megabax, такое исключение является следствием того, что коллекция signals изменяется во время перечисления. Ищите где это у вас происходит.

Цитата Сообщение от megabax Посмотреть сообщение
Выполняю в потоке.
Тогда зачем async\await? Работы в отдельном потоке мало?
0
19 / 19 / 14
Регистрация: 06.08.2009
Сообщений: 533
12.07.2018, 13:46  [ТС] 3
Цитата Сообщение от Usaga Посмотреть сообщение
Тогда зачем async\await? Работы в отдельном потоке мало?
Потому что используется библиотека, в которой методы - асинхронные.
0
Эксперт .NET
12090 / 8369 / 1280
Регистрация: 21.01.2016
Сообщений: 31,548
12.07.2018, 13:49 4
megabax, всё равно решение не особо красивое.

Если код исполняется в потоке отдельном, то может статься, что коллекция signals у вас используется и в другом потоке.
0
19 / 19 / 14
Регистрация: 06.08.2009
Сообщений: 533
12.07.2018, 13:54  [ТС] 5
После замены foreach (Signal signal in signals)
на for(int i=0; i<signals.Count; i++) исключение не вылазит, о что-то понимая почему так мне это не добавило
Вот полный код, что-то нигде не трогает коллекцию signals
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
        /// <summary>
        /// Шаг торговли
        /// </summary>
        /// <param name="current_date">Дата</param>
        /// <param name="driver">Драйвер биржевого терминала</param>
        public async void trade_step(DateTime current_date, ITerminalDriver driver)
        {
            money_manager.positions = await driver.GetPositions();
            foreach (ISignaler signaler in signalers)
            {
                signaler.set_date(current_date);
                List<Signal> signals = signaler.signals;
 
                //отработка принудительного сигнала на покупку
                if(forced_buy_signal && signals.Count==0)
                {
                    BBSignalers BBSig = signaler as BBSignalers;
                    TradeActiveSimbol ac = BBSig.active_simbols[0];
                    Signal forced_signal_buy = new Signal(SignalTypes.buy, ac.active_simbol.simbol);
                    forced_signal_buy.date_time = current_date;
                    forced_signal_buy.trade_active_simbol = ac;
                    forced_buy_signal = false;
                    signals.Add(forced_signal_buy);
                    //forced_buy_signal.price=BBSig.la
                }
 
                if (signaler.signal != null) signals.Add(signaler.signal);
 
                //foreach (Signal signal in signals)
                for(int i=0; i<signals.Count; i++)
                {
                    Signal signal = signals[i];
                    //decimal a = signal.price;
                    //обработаем сигнал
                    MoneyManagerCountInfo count_info = await money_manager.get_count(signal, driver);
 
                    if (count_info.count != 0)
                    {
                        if (count_info.is_entertral)
                        {
                            if (!send_tral(count_info.count, current_date, signaler, signal, driver))
                            {
                                //send_order(count_info.count, current_date, signal, driver);
                            }
                        }
                        else
                        {
                            if (count_info.is_exittral)
                            {
                                if (!send_tral(-count_info.pos, current_date, signaler, signal, driver))
                                {
                                    //send_order(count_info.count, current_date, signal, driver);
                                }
                            }
                            else
                            {
                                //send_order(count_info.count, current_date, signal, driver);
                            }
                        }
                    }
                    //if (count_info.is_close_position) close_all_smart_orders(current_date, driver);
                    /*if (count_info.is_protect_traling_stop && count_info.count != 0)
                    {
                        send_traling_order(count_info.count, current_date, signaler, signal, driver);
                    }*/
                }
 
                do_smart_orders(current_date, driver);
            }
        }
Добавлено через 45 секунд
Цитата Сообщение от Usaga Посмотреть сообщение
Если код исполняется в потоке отдельном, то может статься, что коллекция signals у вас используется и в другом потоке.
Это можно как-то отследить?

Добавлено через 4 минуты
Цитата Сообщение от Usaga Посмотреть сообщение
megabax, всё равно решение не особо красивое.
Вот интересно, какое еще можно придумать решение в таком случае:
у меня была библиотека, натянутая на интерфейс без асинхронных методов через некий враппер.
Затем мне потребовалось натянуть на интерфейс другую библиотеку, соответственно создав для нее такой-же враппер.
Но эта вторая библиотека использует асинхронные методы!
И что я делаю? Меняю интерфейс, переписываю первый враппер и уже с чистой совестью создаю враппер для второй библиотеки, не трогая (ну или почти не трогая) основной код, который использует данный интерфейс.
Как еще можно было сделать?
0
Эксперт .NET
12090 / 8369 / 1280
Регистрация: 21.01.2016
Сообщений: 31,548
12.07.2018, 14:00 6
Цитата Сообщение от megabax Посмотреть сообщение
на for(int i=0; i<signals.Count; i++) исключение не вылазит
Так вы просто скрыли проблему. Изменение коллекции всё ещё продолжается.

Цитата Сообщение от megabax Посмотреть сообщение
что-то нигде не трогает коллекцию signals
Коллекция получается из свойства другого объекта: List<Signal> signals = signaler.signals;, которое может изменяться фиг знает где (в другом потоке).

Цитата Сообщение от megabax Посмотреть сообщение
Это можно как-то отследить?
Синхронизировать все обращения к коллекции из разных потоков. Или, что ещё лучше, не делать так.

Цитата Сообщение от megabax Посмотреть сообщение
Как еще можно было сделать?
Использовать библиотеку в основном потоке, ибо она асинхронная. Или использовать отдельный поток, но вызывать асинхронные методы библиотеки синхронно.
0
19 / 19 / 14
Регистрация: 06.08.2009
Сообщений: 533
12.07.2018, 14:46  [ТС] 7
Цитата Сообщение от Usaga Посмотреть сообщение
Синхронизировать все обращения к коллекции из разных потоков. Или, что ещё лучше, не делать так.
Это как?
Вот так что ли:
C#
1
2
3
4
5
lock (signals)
                {
                    foreach (Signal signal in signals)
                    //for(int i=0; i<signals.Count; i++)
                    {
Добавлено через 31 секунду
но тогда вот на это ругается:
C#
1
MoneyManagerCountInfo count_info = await money_manager.get_count(signal, driver);
0
Эксперт .NET
17685 / 12871 / 3365
Регистрация: 17.09.2011
Сообщений: 21,136
12.07.2018, 15:02 8
Цитата Сообщение от megabax Посмотреть сообщение
Вот полный код, что-то нигде не трогает коллекцию signals
А как она заполняется?
Не забывайте, что await — это потенциальное завершение работы метода, если у вас где-то в другом методе обновляется коллекция signals, а конкретно — обновляются ее элементы вместо создания новых, то это обновление может произойти пока вы ждете завершения задачи get_count.
0
19 / 19 / 14
Регистрация: 06.08.2009
Сообщений: 533
12.07.2018, 15:14  [ТС] 9
Цитата Сообщение от kolorotur Посмотреть сообщение
А как она заполняется?
в методе set_date объекта с интерфейсом ISignaler
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
        /// <summary>
        /// Шаг торговли
        /// </summary>
        /// <param name="current_date">Дата</param>
        /// <param name="driver">Драйвер биржевого терминала</param>
        public async void trade_step(DateTime current_date, ITerminalDriver driver)
        {
            money_manager.positions = await driver.GetPositions();
            foreach (ISignaler signaler in signalers)
            {
                signaler.set_date(current_date);   // ********************** ВОТ ЗДЕСЬ **********************
                List<Signal> signals = signaler.signals;
 
                //отработка принудительного сигнала на покупку
                if(forced_buy_signal && signals.Count==0)
                {
                    BBSignalers BBSig = signaler as BBSignalers;
                    TradeActiveSimbol ac = BBSig.active_simbols[0];
                    Signal forced_signal_buy = new Signal(SignalTypes.buy, ac.active_simbol.simbol);
                    forced_signal_buy.date_time = current_date;
                    forced_signal_buy.trade_active_simbol = ac;
                    forced_buy_signal = false;
                    signals.Add(forced_signal_buy);
                    //forced_buy_signal.price=BBSig.la
                }
 
                if (signaler.signal != null) signals.Add(signaler.signal);
 
                //lock (signals)
                {
                    foreach (Signal signal in signals)
Добавлено через 1 минуту
То есть, когда я выполняю:
C#
1
MoneyManagerCountInfo count_info = await money_manager.get_count(signal, driver);
у меня что, на самом деле поток идет дальше и еще раз заходит в цикл, который внутри trade_step так что ли?
0
Эксперт .NET
17685 / 12871 / 3365
Регистрация: 17.09.2011
Сообщений: 21,136
12.07.2018, 15:31 10
Цитата Сообщение от megabax Посмотреть сообщение
у меня что, на самом деле поток идет дальше и еще раз заходит в цикл, который внутри trade_step так что ли?
Нет, но вполне может быть произведен еще один вызов метода trade_step, который запустит новый цикл.
Если в новом цикле у вас эти коллекции как-то изменяются, то запущенный до этого цикл при следующей итерации будет ругаться.
0
19 / 19 / 14
Регистрация: 06.08.2009
Сообщений: 533
12.07.2018, 16:19  [ТС] 11
Цитата Сообщение от kolorotur Посмотреть сообщение
Нет, но вполне может быть произведен еще один вызов метода trade_step,
Согласно логам, так и есть. Но trade_step вызывается только в этом потоке, больше ни в каком.
Я сделал вот так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
while (trade_thread_is_started)
            {
                if(controller.core!=null) controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "0. trade");
                if (trading_status != TradingStatus.Disabled)
                {
                    controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "1. trade перед началом проверки");
                    if (!trade_contreller_inited) await trade_contreller_init();
                    current_date = await get_current_date();
                    controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "2. trade прошли провреку получи дату all_updated="+all_updated.ToString());
                    if (current_date >= StockUtil.add_intervals(last_candle_time, controller.interval, 1) || last_candle_time==Constants.DataNull || !all_updated)
                    {
                        controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "3. trade сейчас будем догрузить котировки");
                        await load_stocks();
                        controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "4. trade закончили дозагрузку котировок");
                        last_candle_time = StockUtil.round_floor_date_time(current_date, controller.interval);
                    }
                    await Task.Run(() =>
                    {
                        controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "5. trade перед controller.trade_step");
                        controller.trade_step(last_candle_time, driver);
                        controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "6. trade после controller.trade_step");
                    });
                    controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "7. trade");
                    status = "Стоимость портфеля " + (await driver.getPortfolioPrice()).ToString() + " " + (driver as BinanceDriver).base_coin;
                    controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "8. trade");
                    if ((current_date - last_current_date).TotalSeconds > 600 || last_current_date==Constants.DataNull)
                    {
                        (driver as BinanceDriver).update_all_rates();
                        last_current_date = current_date;
                    }
                }
                else
                {
                    controller.reset();
                    trade_contreller_inited = false;
                }
                if (controller.core != null) controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "9. trade перед sleep");
                Thread.Sleep(100);
                if (controller.core != null) controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "10. trade после sleep");
            }
И вот так:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
        /// <summary>
        /// Шаг торговли
        /// </summary>
        /// <param name="current_date">Дата</param>
        /// <param name="driver">Драйвер биржевого терминала</param>
        public async void trade_step(DateTime current_date, ITerminalDriver driver)
        {
            money_manager.positions = await driver.GetPositions();
            foreach (ISignaler signaler in signalers)
            {
                core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "До signaler.set_date(current_date)");
                signaler.set_date(current_date);
                core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "После signaler.set_date(current_date)");
                List<Signal> signals = signaler.signals;
 
                //отработка принудительного сигнала на покупку
                if(forced_buy_signal && signals.Count==0)
                {
                    core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "До принудительный сигнал");
                    BBSignalers BBSig = signaler as BBSignalers;
                    TradeActiveSimbol ac = BBSig.active_simbols[0];
                    Signal forced_signal_buy = new Signal(SignalTypes.buy, ac.active_simbol.simbol);
                    forced_signal_buy.date_time = current_date;
                    forced_signal_buy.trade_active_simbol = ac;
                    forced_buy_signal = false;
                    signals.Add(forced_signal_buy);
                    core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "После принудительный сигнал");
                    //forced_buy_signal.price=BBSig.la
                }
 
                if (signaler.signal != null) signals.Add(signaler.signal);
После этого у меня вывалилось в исключение что файл (куда пишется лог) уже открыт.

Лог пишу вот так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        /// <summary>
        /// Осуществить запись в лог
        /// </summary>
        /// <param name="local_time">Местоное время</param>
        /// <param name="stock_time">Время на бирже</param>
        /// <param name="kind">Вид записи</param>
        /// <param name="msg">Сообщение</param>
        public void writeln(DateTime local_time, DateTime stock_time, LogEventsTypes kind, string msg)
        {
            if (!enabled) return;
            stream = File.AppendText(log_file);
            if (temporary_detail_log && local_time > time_enabled_temporary_detail_log.AddMinutes(temporary_detail_log_time_enable))
                temporary_detail_log = false;
            if (kind == LogEventsTypes.RoutineInfo & !(detail_log || temporary_detail_log)) return;
            string s = local_time.ToString() + "; ";
            if (stock_time != DateTime.MinValue) s = s + stock_time.ToString(); else s = s + "недоступно";
            s = s + "; " + kind.ToString() + "; " + msg + "; ";
            stream.WriteLine(s);
            stream.Close();
        }
В вот что выдает в логе:
12.07.2018 16:32:23; 01.01.2180 0:00:00; Info; 10. trade после sleep;
12.07.2018 16:32:23; 01.01.2180 0:00:00; Info; 0. trade;
12.07.2018 16:32:23; 01.01.2180 0:00:00; Info; 1. trade перед началом проверки;
12.07.2018 16:32:23; 01.01.2180 0:00:00; Info; Начинаем цикл подготовки трейд-контроллера;
12.07.2018 16:32:23; 01.01.2180 0:00:00; Info; controller.init перед;
12.07.2018 16:32:23; 01.01.2180 0:00:00; Info; controller.init после;
12.07.2018 16:32:23; 12.07.2018 12:24:03; Info; 2. trade прошли провреку получи дату all_updated=False;
12.07.2018 16:32:23; 12.07.2018 12:24:03; Info; 3. trade сейчас будем догрузить котировки;
12.07.2018 16:32:23; 12.07.2018 12:24:03; Info; 3.1. load_stocks перед всем all_updated=True;
12.07.2018 16:32:23; 12.07.2018 12:24:03; Info; 3.2. load_stocks перед сигналером all_updated=True;
12.07.2018 16:32:23; 12.07.2018 12:24:00; Info; 3.2.1. Сигналер update res=True;
12.07.2018 16:32:24; 12.07.2018 12:24:03; Info; 3.3. load_stocks после сигналера all_updated=False;
12.07.2018 16:32:24; 12.07.2018 12:24:03; Info; 4. trade закончили дозагрузку котировок;
12.07.2018 16:32:24; 12.07.2018 12:24:03; Info; 5. trade перед controller.trade_step;
12.07.2018 16:32:24; 12.07.2018 12:24:03; Info; 6. trade после controller.trade_step;
12.07.2018 16:32:24; 12.07.2018 12:24:03; Info; 7. trade;
12.07.2018 16:32:25; 12.07.2018 12:24:00; Info; До signaler.set_date(current_date);
12.07.2018 16:32:25; 12.07.2018 12:24:03; Info; 8. trade;
Но не понятно почему До signaler.set_date(current_date); идет после 7. trade; когда реально trade_step вызыается тут:
C#
1
2
3
4
5
6
7
                    await Task.Run(() =>
                    {
                        controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "5. trade перед controller.trade_step");
                        controller.trade_step(last_candle_time, driver); // *********** ТУТ!!!!!!!! ***************
                        controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "6. trade после controller.trade_step");
                    });
                    controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "7. trade");
Добавлено через 10 минут
Думал все дело в блоке

C#
1
2
3
                        controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "5. trade перед controller.trade_step");
                        controller.trade_step(last_candle_time, driver);
                        controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "6. trade после controller.trade_step");
который я обернул в await Task.Run(() =>

сделал эти строки без Task.Run(() => такая же ситуация

Добавлено через 24 минуты
Что то вообще ничего не понимаю.
Даже когда я сделал так
C#
1
2
3
4
5
6
7
                    Task task=Task.Run(() =>
                    {
                        controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "5. trade перед controller.trade_step");
                        controller.trade_step(last_candle_time, driver);
                        controller.core.logger.writeln(DateTime.Now, current_date, LogEventsTypes.Info, "6. trade после controller.trade_step");
                    });
                    while (!task.IsCompleted) Thread.Sleep(10);
все равно лог показывает вот это
12.07.2018 17:24:11; 12.07.2018 13:15:48; Info; 1. trade перед началом проверки;
12.07.2018 17:24:11; 12.07.2018 13:15:50; Info; 2. trade прошли провреку получи дату all_updated=True;
12.07.2018 17:24:11; 12.07.2018 13:15:50; Info; 5. trade перед controller.trade_step;
12.07.2018 17:24:11; 12.07.2018 13:15:50; Info; 6. trade после controller.trade_step;
12.07.2018 17:24:11; 12.07.2018 13:15:50; Info; 7. trade;
12.07.2018 17:24:12; 12.07.2018 13:15:00; Info; До signaler.set_date(current_date);
Почему signaler.set_date(current_date) выполняется после того как я в лог вывел 7. trade; когда я вызываю метод, который вызывает signaler.set_date(current_date) между вот этими строками?
12.07.2018 17:24:11; 12.07.2018 13:15:50; Info; 5. trade перед controller.trade_step;
12.07.2018 17:24:11; 12.07.2018 13:15:50; Info; 6. trade после controller.trade_step;
0
12.07.2018, 16:19
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
12.07.2018, 16:19
Помогаю со студенческими работами здесь

Проблема с меню: Коллекция была изменена; невозможно выполнить операцию перечисления
Здравствуйте, не могу понять вообще что происходит 0_о, вот код: private static TreeView...

Невозможно выполнить операцию перечисления
Всем доброго времени суток! Возникла проблема, ни как не могу понять ее природу. Коллекция была...

Коллекция была изменена; невозможно выполнить операцию перечисления
Добрый день! Явственно не понимаю одну штуку. Ситуация такая: Есть поток, который собирает...

Коллекция была изменена; невозможно выполнить операцию перечисления
Проблема очень простая, иду foreach 'ем по коллекции в которую в это же время добавляю элементы,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru