Потоки Python не работают с pygobject?

Взгляните на эту тривиальную программу gobject на Python:

import threading
import gobject
import time

def f():
    while True:
        print "HELLO"
        time.sleep(1)
threading.Thread(target=f).start()

gobject.MainLoop().run()

Он порождает поток, который выводит «HELLO» каждую секунду, а затем входит в основной цикл объекта. Проблема в том, что он на самом деле ничего не делает. Почему?

$ python a.py 
[...]

Однако, если я нажму CTRL + C, он начнет работать. Кроме того, удаление последней строки в программе (gobject.MainLoop().run()) заставляет ее работать. Почему?

$ python a.py 
^CTraceback (most recent call last):
  File "a.py", line 11, in <module>
    gobject.MainLoop().run()
KeyboardInterruptHELLO

HELLO
HELLO
HELLO
[...]

Взгляните на эту вторую программу, она точно такая же, как и первая, за исключением того, что она говорит gobject запускать функцию g каждую секунду. Этот вид работает, порожденный поток запускается время от времени, а не никогда. Почему?

import threading
import gobject
import time

def f():
    while True:
        print "HELLO"
        time.sleep(1)
threading.Thread(target=f).start()

def g():
    print "yo"
    return True
gobject.timeout_add_seconds(1, g)

gobject.MainLoop().run()

Запуск:

$ python b.py 
HELLOyo

yo
yo
yo
 HELLO
yo
yo
yo
yo
yo
yo
yo
 HELLO
yo
yo
yo
yo
^CTraceback (most recent call last):
  File "b.py", line 16, in <module>
    gobject.MainLoop().run()
KeyboardInterrupt
HELLO
HELLO
HELLO
HELLO
HELLO

И снова нажатие CTRL+C заставляет порожденный поток работать. Почему?

Это использует библиотеку pygobject-2.28.6.


person Dog    schedule 01.05.2013    source источник


Ответы (1)


Вам необходимо инициализировать многопоточность при использовании gobject. Для этого звоните

gobject.threads_init()
person mata    schedule 01.05.2013
comment
Хм, кажется, это исправляет это, но, возможно, это просто совпадение, возможно, из-за изменения порядка одновременных событий. Я считаю абсурдным, что библиотека может нарушить всю среду выполнения, если вы не вызовете в ней функцию перед ее использованием. Кроме того, для приложений, которые хотят использовать потоки Python для взаимодействия с платформой GNOME, необходимо вызвать GObject.threads_init() перед запуском или созданием потоков и запуском основных циклов. не покрывает мой случай, потому что я использую только gobject из основного потока. - person Dog; 01.05.2013
comment
Даже для glib в C, если вы используете GLib более чем из одного потока, вы должны инициализировать систему потоков, вызвав g_thread_init(). (developer.gnome.org/glib/2.30/glib -Threads.html#g-thread-init) - person Dog; 01.05.2013
comment
Я точно не знаю, почему glib mainloop блокирует все остальные потоки, я бы предположил, что он не освобождает GIL во время работы, если вы не инициализируете его правильно. Но я не могу найти никакой ссылки, подтверждающей это (кроме того, что здесь). - person mata; 01.05.2013
comment
github.com/GNOME/pygobject/blob/master/ gi/overrides/GLib.py#L53 говорит: Начиная с версии 3.11 вызов threads_init больше не нужен. См.: wiki.gnome.org/PyGObject/Threading - person Robie Basak; 28.05.2016