Асинхронные функции GPAR и передача ссылок, которые обновляются другим потоком

Я использую асинхронные функции GPAR для запуска процесса при анализе каждой строки в файле.

Я вижу какое-то странное поведение, которое заставляет меня задаться вопросом, есть ли у меня проблема с безопасностью потоков.

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

Uploader {
  MyRowObject currentRowObject
}

Получив все значения из текущей строки, я запускаю асинхронное замыкание, которое выглядит примерно так:

Closure processCurrentRowObject = { ->
    myService.processCurrentRowObject (currentRowObject)
}.asyncFun()

Он определен в том же классе, поэтому имеет доступ к currentRowObject.

Пока он выключен и работает, я анализирую следующую строку и начинаю с создания нового объекта:

MyObject currentObject = new MyObject()

и начните загружать его значениями.

Я предполагал, что это будет безопасно, что асинхронная функция будет указывать на предыдущий объект. Однако мне интересно, потому что я позволяю замыканию привязываться к ссылке, если каким-то образом ссылка обновляется в асинхронной функции, и я, так сказать, вытаскиваю экземпляр объекта из-под него - изменяя его, пока он пытается работать с предыдущим экземпляром.

Если да, какие предложения по исправлению? Или я в безопасности?

Спасибо!


person user1373467    schedule 14.11.2012    source источник


Ответы (1)


Я не уверен, что полностью понимаю ваш случай, однако, вот небольшой совет. Поскольку всегда опасно совместно использовать один изменяемый объект среди потоков, я бы рекомендовал полностью разделить объекты строк, используемые для разных строк:

окончательный localRowObject = currentRowObject currentRowObject = null

Закрытие processCurrentRowObject = { -> myService.processCurrentRowObject (localRowObject) }.asyncFun()

person Vaclav Pech    schedule 15.11.2012
comment
Спасибо... это было немного сложнее, я создавал новый объект для каждой строки, но ссылка на этот текущий объект была переменной-членом. Я изменил его, чтобы сделать копию объекта перед вызовом (по существу) processCurrentRowObject() и передать эту копию. Я думаю, что в своем уме я думал о замыкании как о функции самой по себе, пока она не внутренне ссылалась на внешние по отношению к ней вещи, и все передавалось внутрь. В общем, я хорошо поработал над изоляцией вещей. внутри замыканий с функциональным мышлением, но я думаю, что заводная привязка замыкания привела меня сюда. - person user1373467; 15.11.2012
comment
@Vaclav... один дополнительный вопрос, если вы не возражаете... ответ в этом сообщении (stackoverflow.com/questions/ 11529521/) действительно лучший способ дождаться завершения кучи асинхронных функций? Это могут быть десятки тысяч. Спасибо! - person user1373467; 15.11.2012
comment
Я пошел дальше и опубликовал свой ответ в виде отдельного вопроса: wait-for-completion" title="gpars сообщает о статусе большого количества асинхронных функций и ждет завершения"> stackoverflow.com/questions/13405806/ - person user1373467; 16.11.2012
comment
Еще одно замечание для всех бедолаг, которые найдут здесь дорогу... Я выделил эту проблему в отдельном тесте. Если я передаю переменную в замыкание, все в порядке — я заставляю асинхронную функцию спать, меняю ссылку в основном потоке, чтобы указать на новый объект, а асинхронная функция по-прежнему использует исходный объект. Однако, если я не передаю переменную (currentRowObject) в замыкание, а ссылаюсь на переменную-член Uploader непосредственно внутри замыкания, ее изменение в основном потоке влияет (т. е. асинхронная функция выбирает новый объект из исх.). - person user1373467; 19.11.2012
comment
Теперь, когда я думаю об этом, это более очевидно, но я хотел быть уверен, что передача его в замыкание была безопасной, и это так (если вы измените пример кода выше на что-то вроде этого): - person user1373467; 19.11.2012
comment
Закрытие processCurrentRowObject = {passedRowObject -> myService.processCurrentRowObject (passedRowObject) }.asyncFun() - person user1373467; 19.11.2012