Cython: как печатать без GIL

Как мне использовать print в функции Cython без gil? Например:

from libc.math cimport log, fabs
cpdef double f(double a, double b) nogil:
    cdef double c = log( fabs(a - b) )
    print c
    return c

выдает эту ошибку при компиляции:

Error compiling Cython file:
...
    print c
    ^
------------------------------------------------------------

Python print statement not allowed without gil
...

Я знаю, как использовать библиотеки C вместо их эквивалента python (например, библиотека math здесь), но я не смог найти аналогичный способ для print.


person Behzad Jamali    schedule 21.01.2018    source источник
comment
Зачем тебе это нужно? Вам действительно нужно выпустить GIL только для многопоточности. Использование print из нескольких потоков может легко закончиться просто получением беспорядочного вывода.   -  person DavidW    schedule 21.01.2018
comment
@DavidW Я не использую многопоточность. Я думал, что выпуск GIL избавит Python от накладных расходов (кажется, я ошибался?). В моем случае основной частью моего кода является большой цикл for (около 50 строк кода), но это было мое предположение, и я не проверял, помогает ли выпуск GIL в моем большом коде.   -  person Behzad Jamali    schedule 22.01.2018
comment
Не похоже, что вам нужно быть таким строгим в этом — простое наличие GIL не замедлит вас. Код, который не нуждается в GIL, часто быстрее (как правило), но случайный оператор печати вполне подойдет.   -  person DavidW    schedule 22.01.2018
comment
Я думаю, что этот полезный комментарий заслуживает внимания. Я не знаю, что лучше, но, пожалуйста, не стесняйтесь публиковать это как редактирование моего вопроса или как ответ.   -  person Behzad Jamali    schedule 22.01.2018


Ответы (2)


Используйте printf из stdio:

from libc.stdio cimport printf
...
printf("%f\n", c)
person a spaghetto    schedule 21.01.2018

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

По сути, GIL — это флаг, который содержит каждый поток, чтобы указать, разрешено ли ему вызывать API Python. Простое удерживание флага не стоит вам никакого результата. Cython, как правило, работает быстрее, когда не использует Python API, но это из-за типа операций, которые он выполняет, а не из-за того, что он содержит флаг (т. е. printf, вероятно, немного быстрее, чем Python print, но printf работает с той же скоростью с или без ГИЛ).

Единственный раз, когда вам действительно нужно беспокоиться о GIL, — это при использовании многопоточного кода, когда его освобождение дает возможность запускаться другим потокам Python. (Аналогичным образом, если вы пишете библиотеку и вам не нужен Python API, вероятно, было бы неплохо выпустить GIL, чтобы ваши пользователи могли запускать другие потоки, если они хотят).

Наконец, если вы находитесь в блоке nogil и хотите выполнить быструю операцию Python, вы можете просто сделать:

with gil:
    print c

Скорее всего, это не повлияет на производительность и сэкономит много усилий по программированию.

person DavidW    schedule 22.01.2018