Pull to refresh
93
0
Андрей Светлов @svetlov

User

Send message
Ага, это не просто дочерние процессы а multiprocessing.Pool, что несколько меняет дело.
pool.close()
pool.join()

делали?

Без этого pool дочерние процессы не закрывает.
Вот вам ссылка: docs.python.org/2/library/multiprocessing.html#multiprocessing.pool.multiprocessing.Pool.close
Что-то вы дивное рассказываете.
Можете привести подробности?
Прошу прощения, вместо GIT нужно читать JIT.
неймспейс по русски — пространство имён.
Устоявшегося русскоязычного термина нет — так что, как мне кажется, лучше расшифровывать а не использовать транслитерацию.
Можно выделить курсивом чтобы подчеркнуть особое использование этих слов.
Проблема не только в том что «ребята не желают».

Оставим на минутку вопросы совместимости Python C API и всех уже написанных Python C Extensions (а одно только это требует срочного запуска Python 4 и мучительной миграции в то время как на Python 3 ещё далеко не все перешли).

Software Transactional Memory всё ещё в стадии эксперимента.
Армин Риго хорошо поработал, но STM всё еще не вошла в релиз PyPy.
Потому что тормозит и падает иногда.

Так что, прошу, не надо категорических заявлений.

Слова про «вывод типов» — не понял о чём это.

Про оптимизацию памяти — как раз PyPy кушает её как не родной именно из-за GIT.

К тому же GIT сильно тормозит запуск консольных утилит.
Он просто не успевает «разогреться» к тому моменту как программа закончилась.
По этой же причине юниттесты на PyPy могут выполняться дольше чем на CPython.

В общем, нет серебрянной пули.
Молодец! Продолжай дальше!

Документация внутренности покрывает очень слабо.
На английском можно найти кое-что (очень мало если честно).
В основном это исходники и внутренние ресурсы (багтрекер и рассылка).

На русском практичеси вообще ничего нет.

Я не хочу заниматься переводами сам, но если тебе это нравится — морально поддерживаю со всех сил.
Документация не совсем точна. Следующий параграф Note более внятно описывает что именно происходит
Про __del__ неправильно написано. Метод будет вызван если интертретатор завершает работу.
Другое дело что он не вызовется сборщиком мусора (объекты с __del__ сборщик мусора до версии 3.4 не умеет обрабатывать вообще).
__del__ работает только если произошел decref, а не garbage collection.
Для CPython — немедленно. В других реализациях чаще используют подход Java и там нет счётчика ссылок вообще.
Написал asvetlov.blogspot.com/2013/05/gc.html в качестве подробного объяснения.
Спасибо, что своим постом помогли мне оформить свои мысли.
Пороги в gc жесткие. Нужно понимать, что они означают.
Garbage collector срабатывает, если с момента последнего запуска gc.collect() количество созданных объектов превысило количество удалённых в конкретном поколении на пороговое значение.
Не количество объектов в поколении вообще, а именно разница между созданными и удаленными.
Да, кстати. В 3.3 есть занятная штука — docs.python.org/3/library/gc#gc.callbacks
Переключение GIL может произойти перед выполнением любого байткода. Так что всё верно: ваш пример не атомарный.
Всё верно, нужно перелопатить много кода, причем основной объем в третьесторонних библиотеках. PEP 3121 не предлагает «контекст», он только дает место для хранения переменных модуля и всё.
Если быть точным, namespace внутри использует pickle или xmlrpclib.
Фактически все нетривиальные (не int, float, str) типы используют сериализацию. Т.к. picke обычно замечательно работает для multiprocessing «из коробки» — никаких неудобств это не доставляет и происходит незаметно для программиста.
Субинтерпретаторы не обязаны работать в разных потоках. Т.е. должна поддерживаться в том числе и схема, при которой несколько субинтерпретаторов разделяют один поток. threadlocal здесь не помогут.
Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS позволяют параллельное выполнение даже в питоновских потоках.

И, естественно, ничто не мешает создавать отдельные потоки, о которых Питон ничего не знает.

Только Python API без GIL вызывать нельзя. Хоть и очень хочется.

К слову, PyGILState_Ensure/PyGILState_Release — довольно дорогая операция.
Лучше делать её один раз на поток, используя PyEval_SaveThread/PyEval_RestoreThread для временного отпускания GIL.
Полагаю, к версии 4.0
bugs.python.org/issue15751 если будет сделан поможет написать работу с субинтерпретаторами правильно (PyGILState_Ensure умеет жить только с главным интерпретатором если что).

Основная беда следующая: субинтерпретаторы разделяют слишком много данных. Если питоновский код еще можно как-то развести по углам, то с C Extensions полная беда.

По сложившейся практике данные модуля все хранят как static variables. Существует PEP 3121 для module state, но пока его никто не реализовывает (благо что необязательный).
В коде я увидел, что субинтерпретаторы захватывают GIL перед использованием (отчего-то два раза, но это не принципиально).

После этого код в ThreadWork::operator() выполняется уже не параллельно с другими ThreadWork (GIL-то один).

Для демонстрации вызов ctimer.wait() можно заменить на boost::this_thread::sleep()

Опять же для усугубления эффекта рекомендую увеличить паузу с полусекунды раз в 10-100.

Information

Rating
Does not participate
Location
Киев, Киевская обл., Украина
Registered
Activity