Безопасно ли использовать Intvar/DoubleVar в потоке Python?
Позвольте мне просто предсказать это, сказав, что я почти наверняка буду использовать Queue
для моей программы. Я публикую этот вопрос, чтобы более или менее просто удовлетворить свое любопытство, потратив приличное количество времени на исследование этой темы, не найдя каких-либо окончательных ответов.
Итак, вопрос: это безопасно для доступа / редактирования IntVar()
, DoubleVar()
и т. д., кроме как из основного цикла? Кроме того, как насчет простого чтения значения (через x.get()
) из отдельной ветки? Я знаю, что не следует редактировать / обновлять виджеты из отдельных потоков, но я не нашел никакой информации относительно Intvars и тому подобного. Любое понимание будет с благодарностью.
Вот связанный (но довольно старый) вопрос, на который так и не был дан ответ:
Python / Tkinter: Является ли Tkinter StringVar (IntVar и т. Д.) Потокобезопасным?
1 ответ
На основе комментариев в исходном коде для _tkinter
Похоже, что модуль tkinter на самом деле предназначен для работы с потоками, если Tcl был собран с --enable-threads
вариант. Это подтверждается исправленной ошибкой на трекере Python ( проблема11077), утверждающей, что tkinter не является поточно-ориентированным, и в конечном итоге было установлено, что все проблемы с безопасностью потоков с tkinter были ошибками, которые были исправлены в Python 2.7.3+
Вот что _tkinter
Источник модуля говорит по этому вопросу:
Интерпретатор Tcl действителен только в потоке, который его создал, и вся активность Tk также должна происходить в этом потоке. Это означает, что mainloop должен быть вызван в потоке, который создал интерпретатор. Вызов команд из других потоков возможен; _tkinter поставит в очередь событие для потока интерпретатора, который затем выполнит команду и вернет результат. Если основной поток не находится в mainloop, и вызов команд вызывает исключение; если основной цикл выполняется, но не обрабатывает события, вызов команды будет заблокирован.
Таким образом, пока mainloop активно работает в главном потоке приложения, tkinter будет планировать автоматический запуск метода в главном потоке, что сделает его поточно-ориентированным. Тем не менее, большинство источников в Интернете, за исключением фактического исходного кода Tkinter и вышеприведенного отчета об ошибках, указывают, что использование tkinter с потоками вызывает сбой. Я не совсем уверен, во что верить, хотя в некоторых небольших примерах я пытался обновить GUI из потока.
Теперь вам было интересно, применяются ли правила безопасности потоков, связанные с виджетами Tk, к Variable
подклассы тоже. Это делает: Вот некоторые из реализации Variable
родитель IntVar
:
class Variable:
_default = ""
_tk = None
def __init__(self, master=None, value=None, name=None):
"""Construct a variable
MASTER can be given as master widget.
VALUE is an optional value (defaults to "")
NAME is an optional Tcl name (defaults to PY_VARnum).
If NAME matches an existing variable and VALUE is omitted
then the existing value is retained.
"""
# ...snip...
if not master:
master = _default_root
self._master = master
self._tk = master.tk
def set(self, value):
"""Set the variable to VALUE."""
return self._tk.globalsetvar(self._name, value)
Когда ты set
переменная, она вызывает globalsetvar
метод на главном виджете, связанном с Variable
, _tk.globalsetvar
метод реализован на C и внутренне вызывает var_invoke
, который внутренне называет WaitForMainLoop
, который попытается запланировать выполнение команды в главном потоке, как описано в цитате из _tkinter
источник я включил выше.
static PyObject*
var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags)
{
/* snip */
/* The current thread is not the interpreter thread. Marshal
the call to the interpreter thread, then wait for
completion. */
if (!WaitForMainloop(self))
return NULL;
/* snip */
static PyObject *
Tkapp_GlobalSetVar(PyObject *self, PyObject *args)
{
return var_invoke(SetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
}
Обратите внимание, что этот путь к коду используется и для операций get, поэтому оба set
а также get
операции регулируются по тем же правилам.