Да, вы можете! Это называется sshfs.
Основная идея:
Установить sshfssudo apt install sshfs
Установить удаленный каталог sshfs user@host:/path/to/remote /path/to/local/mount/point
Теперь у вас есть пульт дистанционного управления каталог /path/to/remote доступен в /path/to/local/mount/point.
Ваша проблема очень распространенная, поэтому есть множество решений (сараи, очереди с многопроцессорной или поточной обработкой, пулы рабочих, ...)
Поскольку это так часто, существует также python встроенное решение (в 3.2, но backported здесь: http://pypi.python.org/pypi/futures), называемое concurrent.futures. «Фьючерсы» доступны на многих языках, поэтому питон называет их одинаковыми. Вот типичные вызовы (и вот ваш полный пример, однако, часть db заменяется на сон, см. Ниже почему).
from concurrent import futures
executor = futures.ProcessPoolExecutor(max_workers=1)
#executor = futures.ThreadPoolExecutor(max_workers=1)
future = executor.submit(slow_load)
future.add_done_callback(self.on_complete)
Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:
Большинство реализаций на Python имеют GIL, что делает потоки не полностью использующими multicores. Итак: не используйте потоки с python! Объекты, которые вы хотите вернуть в slow_load из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра! Библиотека, которую вы вызываете (softwarecenter.db), не является потокобезопасной (кажется, включает в себя gtk или аналогичную), поэтому вызов этих методов в потоке приводит к странному поведению (в моем тесте все от «работает» над «дампом ядра» до простого отказ от результатов). Итак: нет потоков с программным центром. Каждый асинхронный обратный вызов в gtk не должен делать ничего, кроме того, что нужно отсылать обратный вызов, который будет вызываться в glib mainloop. Итак: no print, никаких изменений состояния gtk, кроме добавления обратного вызова! Gtk и так не работают с потоками из коробки. Вам нужно сделать threads_init, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter(), gtk.gdk.threads_leave(). См., Например, gstreamer: http: //pygstdocs.berlios .de / pygst-учебник / playbin.html).Я могу дать вам следующее предложение:
Большинство реализаций на Python имеют GIL, что делает потоки не полностью использующими multicores. Итак: не используйте потоки с python! Переключитесь с softwarecenter на python-apt или аналогичные (вам, вероятно, это не нравится). Но так как вы наняли Canonical, вы могли бы попросить разработчиков программного обеспечения непосредственно not к их программному обеспечению (например, заявив, что он не является потокобезопасным) и даже лучше, делая программный центр потокобезопасным.В качестве примечания: решения, заданные другими (Gio.io_scheduler_push_job, async_call), работают с time.sleep, но не с softwarecenter.db. Это потому, что все это сводится к потокам, процессам и потокам, которые не работают с gtk и softwarecenter.
Ваша проблема очень распространенная, поэтому есть множество решений (сараи, очереди с многопроцессорной или поточной обработкой, пулы рабочих, ...)
. Поскольку это так распространено, python встроенное решение (в 3.2, но backported здесь: http://pypi.python.org/pypi/futures ), называемое concurrent.futures. «Фьючерсы» доступны на многих языках, поэтому питон называет их одинаковыми. Вот типичные вызовы (и вот ваш полный пример , однако, часть db заменяется на сон, см. Ниже почему).
from concurrent import futures
executor = futures.ProcessPoolExecutor(max_workers=1)
#executor = futures.ThreadPoolExecutor(max_workers=1)
future = executor.submit(slow_load)
future.add_done_callback(self.on_complete)
Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:
slow_load
из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра! print
, никаких изменений состояния gtk, кроме добавления обратного вызова! threads_init
, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter()
, gtk.gdk.threads_leave()
. См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).Я могу дать вам следующее предложение:
slow_load
, чтобы возвращать собранные результаты и использовать фьючерсы с процессами. As примечание: решения, заданные другими (Gio.io_scheduler_push_job
, async_call
), работают с time.sleep
, но не с softwarecenter.db
. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter
.
Ваша проблема очень распространенная, поэтому есть множество решений (сараи, очереди с многопроцессорной или поточной обработкой, пулы рабочих, ...)
. Поскольку это так распространено, python встроенное решение (в 3.2, но backported здесь: http://pypi.python.org/pypi/futures ), называемое concurrent.futures. «Фьючерсы» доступны на многих языках, поэтому питон называет их одинаковыми. Вот типичные вызовы (и вот ваш полный пример , однако, часть db заменяется на сон, см. Ниже почему).
from concurrent import futures
executor = futures.ProcessPoolExecutor(max_workers=1)
#executor = futures.ThreadPoolExecutor(max_workers=1)
future = executor.submit(slow_load)
future.add_done_callback(self.on_complete)
Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:
slow_load
из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра! print
, никаких изменений состояния gtk, кроме добавления обратного вызова! threads_init
, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter()
, gtk.gdk.threads_leave()
. См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).Я могу дать вам следующее предложение:
slow_load
, чтобы возвращать собранные результаты и использовать фьючерсы с процессами. As примечание: решения, заданные другими (Gio.io_scheduler_push_job
, async_call
), работают с time.sleep
, но не с softwarecenter.db
. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter
.
Ваша проблема очень распространенная, поэтому есть множество решений (сараи, очереди с многопроцессорной или поточной обработкой, пулы рабочих, ...)
. Поскольку это так распространено, python встроенное решение (в 3.2, но backported здесь: http://pypi.python.org/pypi/futures ), называемое concurrent.futures. «Фьючерсы» доступны на многих языках, поэтому питон называет их одинаковыми. Вот типичные вызовы (и вот ваш полный пример , однако, часть db заменяется на сон, см. Ниже почему).
from concurrent import futures
executor = futures.ProcessPoolExecutor(max_workers=1)
#executor = futures.ThreadPoolExecutor(max_workers=1)
future = executor.submit(slow_load)
future.add_done_callback(self.on_complete)
Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:
slow_load
из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра! print
, никаких изменений состояния gtk, кроме добавления обратного вызова! threads_init
, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter()
, gtk.gdk.threads_leave()
. См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).Я могу дать вам следующее предложение:
slow_load
, чтобы возвращать собранные результаты и использовать фьючерсы с процессами. As примечание: решения, заданные другими (Gio.io_scheduler_push_job
, async_call
), работают с time.sleep
, но не с softwarecenter.db
. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter
.
Ваша проблема очень распространенная, поэтому есть множество решений (сараи, очереди с многопроцессорной или поточной обработкой, пулы рабочих, ...)
. Поскольку это так распространено, python встроенное решение (в 3.2, но backported здесь: http://pypi.python.org/pypi/futures ), называемое concurrent.futures. «Фьючерсы» доступны на многих языках, поэтому питон называет их одинаковыми. Вот типичные вызовы (и вот ваш полный пример , однако, часть db заменяется на сон, см. Ниже почему).
from concurrent import futures
executor = futures.ProcessPoolExecutor(max_workers=1)
#executor = futures.ThreadPoolExecutor(max_workers=1)
future = executor.submit(slow_load)
future.add_done_callback(self.on_complete)
Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:
slow_load
из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра! print
, никаких изменений состояния gtk, кроме добавления обратного вызова! threads_init
, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter()
, gtk.gdk.threads_leave()
. См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).Я могу дать вам следующее предложение:
slow_load
, чтобы возвращать собранные результаты и использовать фьючерсы с процессами. As примечание: решения, заданные другими (Gio.io_scheduler_push_job
, async_call
), работают с time.sleep
, но не с softwarecenter.db
. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter
.
Ваша проблема очень распространенная, поэтому есть множество решений (сараи, очереди с многопроцессорной или поточной обработкой, пулы рабочих, ...)
. Поскольку это так распространено, python встроенное решение (в 3.2, но backported здесь: http://pypi.python.org/pypi/futures ), называемое concurrent.futures. «Фьючерсы» доступны на многих языках, поэтому питон называет их одинаковыми. Вот типичные вызовы (и вот ваш полный пример , однако, часть db заменяется на сон, см. Ниже почему).
from concurrent import futures
executor = futures.ProcessPoolExecutor(max_workers=1)
#executor = futures.ThreadPoolExecutor(max_workers=1)
future = executor.submit(slow_load)
future.add_done_callback(self.on_complete)
Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:
slow_load
из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра! print
, никаких изменений состояния gtk, кроме добавления обратного вызова! threads_init
, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter()
, gtk.gdk.threads_leave()
. См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).Я могу дать вам следующее предложение:
slow_load
, чтобы возвращать собранные результаты и использовать фьючерсы с процессами. As примечание: решения, заданные другими (Gio.io_scheduler_push_job
, async_call
), работают с time.sleep
, но не с softwarecenter.db
. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter
.
Ваша проблема очень распространенная, поэтому есть множество решений (сараи, очереди с многопроцессорной или поточной обработкой, пулы рабочих, ...)
. Поскольку это так распространено, python встроенное решение (в 3.2, но backported здесь: http://pypi.python.org/pypi/futures ), называемое concurrent.futures. «Фьючерсы» доступны на многих языках, поэтому питон называет их одинаковыми. Вот типичные вызовы (и вот ваш полный пример , однако, часть db заменяется на сон, см. Ниже почему).
from concurrent import futures
executor = futures.ProcessPoolExecutor(max_workers=1)
#executor = futures.ThreadPoolExecutor(max_workers=1)
future = executor.submit(slow_load)
future.add_done_callback(self.on_complete)
Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:
slow_load
из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра! print
, никаких изменений состояния gtk, кроме добавления обратного вызова! threads_init
, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter()
, gtk.gdk.threads_leave()
. См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).Я могу дать вам следующее предложение:
slow_load
, чтобы возвращать собранные результаты и использовать фьючерсы с процессами. As примечание: решения, заданные другими (Gio.io_scheduler_push_job
, async_call
), работают с time.sleep
, но не с softwarecenter.db
. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter
.
Ваша проблема очень распространенная, поэтому есть множество решений (сараи, очереди с многопроцессорной или поточной обработкой, пулы рабочих, ...)
. Поскольку это так распространено, python встроенное решение (в 3.2, но backported здесь: http://pypi.python.org/pypi/futures ), называемое concurrent.futures. «Фьючерсы» доступны на многих языках, поэтому питон называет их одинаковыми. Вот типичные вызовы (и вот ваш полный пример , однако, часть db заменяется на сон, см. Ниже почему).
from concurrent import futures
executor = futures.ProcessPoolExecutor(max_workers=1)
#executor = futures.ThreadPoolExecutor(max_workers=1)
future = executor.submit(slow_load)
future.add_done_callback(self.on_complete)
Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:
slow_load
из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра! print
, никаких изменений состояния gtk, кроме добавления обратного вызова! threads_init
, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter()
, gtk.gdk.threads_leave()
. См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).Я могу дать вам следующее предложение:
slow_load
, чтобы возвращать собранные результаты и использовать фьючерсы с процессами. As примечание: решения, заданные другими (Gio.io_scheduler_push_job
, async_call
), работают с time.sleep
, но не с softwarecenter.db
. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter
.
Вот еще один вариант с использованием планировщика ввода-вывода GIO (я никогда не использовал его раньше из Python, но пример ниже, похоже, работает нормально).
from gi.repository import GLib, Gio, GObject
import time
def slow_stuff(job, cancellable, user_data):
print "Slow!"
for i in xrange(5):
print "doing slow stuff..."
time.sleep(0.5)
print "finished doing slow stuff!"
return False # job completed
def main():
GObject.threads_init()
print "Starting..."
Gio.io_scheduler_push_job(slow_stuff, None, GLib.PRIORITY_DEFAULT, None)
print "It's running async..."
GLib.idle_add(ui_stuff)
GLib.MainLoop().run()
def ui_stuff():
print "This is the UI doing stuff..."
time.sleep(1)
return True
if __name__ == '__main__':
main()
Вы также можете использовать GLib.idle_add (callback) для вызова долговременной задачи после того, как GLib Mainloop завершит все события с более высоким приоритетом (которые, я считаю, включает в себя создание пользовательского интерфейса).
Использовать интроспективный API Gio для чтения файла с его асинхронными методами и при выполнении начального вызова сделать это как тайм-аут с GLib.timeout_add_seconds(3, call_the_gio_stuff), где call_the_gio_stuff - это функция, которая возвращает False. [ ! d0]
Тайм-аут здесь необходимо добавить (может потребоваться другое количество секунд), потому что, хотя вызовы асинхронного вызова Gio являются асинхронными, они не являются неблокирующими, что означает, что активность жесткого диска чтения большой файл или большое количество файлов, может привести к заблокированному пользовательскому интерфейсу, поскольку пользовательский интерфейс и ввод-вывод все еще находятся в одном и том же (основном) потоке.
Если вы хотите написать свои собственные функции async и интегрироваться с основным циклом, используя API-интерфейсы ввода-вывода файлов Python, вам нужно будет написать код в виде GObject или передать обратные вызовы или использовать python-defer, чтобы помочь вам это сделать. Но лучше использовать Gio здесь, так как это может принести вам массу приятных функций, особенно если вы делаете файл открытым / сохраненным в UX.
Я думаю, что это означает, что это сложный способ сделать то, что предложил @mhall.
По сути, у вас есть запуск, а затем запустите эту функцию async_call.
Если вы хотите посмотреть, как это работает, вы можете играть с таймером сна и продолжать нажимать кнопку. Это по сути то же самое, что и ответ @ mhall, за исключением того, что есть пример кода.
Исходя из этого, что не является моей работой.
import threading
import time
from gi.repository import Gtk, GObject
# calls f on another thread
def async_call(f, on_done):
if not on_done:
on_done = lambda r, e: None
def do_call():
result = None
error = None
try:
result = f()
except Exception, err:
error = err
GObject.idle_add(lambda: on_done(result, error))
thread = threading.Thread(target = do_call)
thread.start()
class SlowLoad(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
GObject.threads_init()
self.connect("delete-event", Gtk.main_quit)
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
self.file_contents = 'Slow load pending'
async_call(self.slow_load, self.slow_complete)
def on_button_clicked(self, widget):
print self.file_contents
def slow_complete(self, results, errors):
'''
'''
self.file_contents = results
self.button.set_label(self.file_contents)
self.button.show_all()
def slow_load(self):
'''
'''
time.sleep(5)
self.file_contents = "Slow load in progress..."
time.sleep(5)
return 'Slow load complete'
if __name__ == '__main__':
win = SlowLoad()
win.show_all()
#time.sleep(10)
Gtk.main()
Дополнительно обратите внимание, что вы должны разрешить другой поток до того, как он завершится правильно или проверит файл file.lock в дочернем потоке.
Редактировать комментарий к адресу: Первоначально я забыл GObject.threads_init(). Очевидно, когда кнопка срабатывала, для меня была инициализирована резьба. Это замаскировало ошибку для меня.
Как правило, поток создает окно в памяти, сразу же запускает другой поток, когда поток завершает обновление кнопки. Я добавил дополнительный сон, прежде чем я даже позвонил в Gtk.main, чтобы убедиться, что полное обновление COULD запустилось до того, как окно было даже рисовано. Я также прокомментировал это, чтобы убедиться, что запуск потока не мешает рисованию окна.
Использовать интроспективный API Gio
для чтения файла с его асинхронными методами и при выполнении начального вызова сделать это как тайм-аут с GLib.timeout_add_seconds(3, call_the_gio_stuff)
, где call_the_gio_stuff
- это функция, которая возвращает False
.
Тайм-аут здесь необходимо добавить (может потребоваться другое количество секунд), так как в то время как асинхронные вызовы Gio являются асинхронными, они не являются неблокирующими, что означает, что активность жесткого диска чтения большой файл или большое количество файлов, может привести к блокированному пользовательскому интерфейсу, поскольку пользовательский интерфейс и ввод-вывод все еще находятся в одном и том же (основном) потоке.
Если вы хотите написать свои собственные функции, async и интегрироваться с основным циклом, используя API-интерфейсы ввода-вывода файлов Python, вам нужно будет написать код в виде GObject или передать обратные вызовы или использовать python-defer
, чтобы помочь вам это сделать. Но лучше использовать Gio здесь, так как он может принести вам массу приятных функций, особенно если вы делаете файл открытым / сохраненным в UX.
Вы также можете использовать GLib.idle_add (обратный вызов) для вызова долговременной задачи, когда GLib Mainloop завершает все события с более высоким приоритетом (которые, я считаю, включает в себя создание пользовательского интерфейса).
Вот еще один вариант с использованием планировщика ввода-вывода GIO (я никогда раньше не использовал его с Python, но пример ниже, похоже, работает нормально).
from gi.repository import GLib, Gio, GObject
import time
def slow_stuff(job, cancellable, user_data):
print "Slow!"
for i in xrange(5):
print "doing slow stuff..."
time.sleep(0.5)
print "finished doing slow stuff!"
return False # job completed
def main():
GObject.threads_init()
print "Starting..."
Gio.io_scheduler_push_job(slow_stuff, None, GLib.PRIORITY_DEFAULT, None)
print "It's running async..."
GLib.idle_add(ui_stuff)
GLib.MainLoop().run()
def ui_stuff():
print "This is the UI doing stuff..."
time.sleep(1)
return True
if __name__ == '__main__':
main()
Использовать интроспективный API Gio
для чтения файла с его асинхронными методами и при выполнении начального вызова сделать это как тайм-аут с GLib.timeout_add_seconds(3, call_the_gio_stuff)
, где call_the_gio_stuff
- это функция, которая возвращает False
.
Тайм-аут здесь необходимо добавить (может потребоваться другое количество секунд), так как в то время как асинхронные вызовы Gio являются асинхронными, они не являются неблокирующими, что означает, что активность жесткого диска чтения большой файл или большое количество файлов, может привести к блокированному пользовательскому интерфейсу, поскольку пользовательский интерфейс и ввод-вывод все еще находятся в одном и том же (основном) потоке.
Если вы хотите написать свои собственные функции, async и интегрироваться с основным циклом, используя API-интерфейсы ввода-вывода файлов Python, вам нужно будет написать код в виде GObject или передать обратные вызовы или использовать python-defer
, чтобы помочь вам это сделать. Но лучше использовать Gio здесь, так как он может принести вам массу приятных функций, особенно если вы делаете файл открытым / сохраненным в UX.
Вы также можете использовать GLib.idle_add (обратный вызов) для вызова долговременной задачи, когда GLib Mainloop завершает все события с более высоким приоритетом (которые, я считаю, включает в себя создание пользовательского интерфейса).
Я думаю, что это означает, что это сложный способ сделать то, что предложил @mhall.
По сути, у вас есть запуск, затем запустите эту функцию async_call.
Если вы хотите посмотреть, как это работает, вы можете играть с таймером сна и продолжать нажимать кнопку. [Gg]
Исходя из этого , который не является моей работой.
import threading
import time
from gi.repository import Gtk, GObject
# calls f on another thread
def async_call(f, on_done):
if not on_done:
on_done = lambda r, e: None
def do_call():
result = None
error = None
try:
result = f()
except Exception, err:
error = err
GObject.idle_add(lambda: on_done(result, error))
thread = threading.Thread(target = do_call)
thread.start()
class SlowLoad(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
GObject.threads_init()
self.connect("delete-event", Gtk.main_quit)
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
self.file_contents = 'Slow load pending'
async_call(self.slow_load, self.slow_complete)
def on_button_clicked(self, widget):
print self.file_contents
def slow_complete(self, results, errors):
'''
'''
self.file_contents = results
self.button.set_label(self.file_contents)
self.button.show_all()
def slow_load(self):
'''
'''
time.sleep(5)
self.file_contents = "Slow load in progress..."
time.sleep(5)
return 'Slow load complete'
if __name__ == '__main__':
win = SlowLoad()
win.show_all()
#time.sleep(10)
Gtk.main()
Дополнительно, вы должны допустить, чтобы другой поток завершился до того, как он завершится правильно или проверьте файл file.lock в дочернем потоке.
Редактировать комментарий к адресу: Первоначально я забыл GObject.threads_init()
. Очевидно, когда кнопка срабатывала, для меня была инициализирована резьба. Это замаскировало ошибку для меня.
Обычно поток создает окно в памяти, сразу же запускает другой поток, когда поток завершает обновление кнопки. Я добавил дополнительный сон, прежде чем я даже позвонил в Gtk.main, чтобы убедиться, что полное обновление COULD запустилось до того, как окно было даже рисовано. Я также прокомментировал это, чтобы убедиться, что запуск потока не мешает рисованию окна.
Вот еще один вариант с использованием планировщика ввода-вывода GIO (я никогда раньше не использовал его с Python, но пример ниже, похоже, работает нормально).
from gi.repository import GLib, Gio, GObject
import time
def slow_stuff(job, cancellable, user_data):
print "Slow!"
for i in xrange(5):
print "doing slow stuff..."
time.sleep(0.5)
print "finished doing slow stuff!"
return False # job completed
def main():
GObject.threads_init()
print "Starting..."
Gio.io_scheduler_push_job(slow_stuff, None, GLib.PRIORITY_DEFAULT, None)
print "It's running async..."
GLib.idle_add(ui_stuff)
GLib.MainLoop().run()
def ui_stuff():
print "This is the UI doing stuff..."
time.sleep(1)
return True
if __name__ == '__main__':
main()
Я думаю, что это означает, что это сложный способ сделать то, что предложил @mhall.
По сути, у вас есть запуск, затем запустите эту функцию async_call.
Если вы хотите посмотреть, как это работает, вы можете играть с таймером сна и продолжать нажимать кнопку. [Gg]
Исходя из этого , который не является моей работой.
import threading
import time
from gi.repository import Gtk, GObject
# calls f on another thread
def async_call(f, on_done):
if not on_done:
on_done = lambda r, e: None
def do_call():
result = None
error = None
try:
result = f()
except Exception, err:
error = err
GObject.idle_add(lambda: on_done(result, error))
thread = threading.Thread(target = do_call)
thread.start()
class SlowLoad(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
GObject.threads_init()
self.connect("delete-event", Gtk.main_quit)
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
self.file_contents = 'Slow load pending'
async_call(self.slow_load, self.slow_complete)
def on_button_clicked(self, widget):
print self.file_contents
def slow_complete(self, results, errors):
'''
'''
self.file_contents = results
self.button.set_label(self.file_contents)
self.button.show_all()
def slow_load(self):
'''
'''
time.sleep(5)
self.file_contents = "Slow load in progress..."
time.sleep(5)
return 'Slow load complete'
if __name__ == '__main__':
win = SlowLoad()
win.show_all()
#time.sleep(10)
Gtk.main()
Дополнительно, вы должны допустить, чтобы другой поток завершился до того, как он завершится правильно или проверьте файл file.lock в дочернем потоке.
Редактировать комментарий к адресу: Первоначально я забыл GObject.threads_init()
. Очевидно, когда кнопка срабатывала, для меня была инициализирована резьба. Это замаскировало ошибку для меня.
Обычно поток создает окно в памяти, сразу же запускает другой поток, когда поток завершает обновление кнопки. Я добавил дополнительный сон, прежде чем я даже позвонил в Gtk.main, чтобы убедиться, что полное обновление COULD запустилось до того, как окно было даже рисовано. Я также прокомментировал это, чтобы убедиться, что запуск потока не мешает рисованию окна.
Вот еще один вариант с использованием планировщика ввода-вывода GIO (я никогда раньше не использовал его с Python, но пример ниже, похоже, работает нормально).
from gi.repository import GLib, Gio, GObject
import time
def slow_stuff(job, cancellable, user_data):
print "Slow!"
for i in xrange(5):
print "doing slow stuff..."
time.sleep(0.5)
print "finished doing slow stuff!"
return False # job completed
def main():
GObject.threads_init()
print "Starting..."
Gio.io_scheduler_push_job(slow_stuff, None, GLib.PRIORITY_DEFAULT, None)
print "It's running async..."
GLib.idle_add(ui_stuff)
GLib.MainLoop().run()
def ui_stuff():
print "This is the UI doing stuff..."
time.sleep(1)
return True
if __name__ == '__main__':
main()
Использовать интроспективный API Gio
для чтения файла с его асинхронными методами и при выполнении начального вызова сделать это как тайм-аут с GLib.timeout_add_seconds(3, call_the_gio_stuff)
, где call_the_gio_stuff
- это функция, которая возвращает False
.
Тайм-аут здесь необходимо добавить (может потребоваться другое количество секунд), так как в то время как асинхронные вызовы Gio являются асинхронными, они не являются неблокирующими, что означает, что активность жесткого диска чтения большой файл или большое количество файлов, может привести к блокированному пользовательскому интерфейсу, поскольку пользовательский интерфейс и ввод-вывод все еще находятся в одном и том же (основном) потоке.
Если вы хотите написать свои собственные функции, async и интегрироваться с основным циклом, используя API-интерфейсы ввода-вывода файлов Python, вам нужно будет написать код в виде GObject или передать обратные вызовы или использовать python-defer
, чтобы помочь вам это сделать. Но лучше использовать Gio здесь, так как он может принести вам массу приятных функций, особенно если вы делаете файл открытым / сохраненным в UX.
Я думаю, что это означает, что это сложный способ сделать то, что предложил @mhall.
По сути, у вас есть запуск, затем запустите эту функцию async_call.
Если вы хотите посмотреть, как это работает, вы можете играть с таймером сна и продолжать нажимать кнопку. [Gg]
Исходя из этого , который не является моей работой.
import threading
import time
from gi.repository import Gtk, GObject
# calls f on another thread
def async_call(f, on_done):
if not on_done:
on_done = lambda r, e: None
def do_call():
result = None
error = None
try:
result = f()
except Exception, err:
error = err
GObject.idle_add(lambda: on_done(result, error))
thread = threading.Thread(target = do_call)
thread.start()
class SlowLoad(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
GObject.threads_init()
self.connect("delete-event", Gtk.main_quit)
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
self.file_contents = 'Slow load pending'
async_call(self.slow_load, self.slow_complete)
def on_button_clicked(self, widget):
print self.file_contents
def slow_complete(self, results, errors):
'''
'''
self.file_contents = results
self.button.set_label(self.file_contents)
self.button.show_all()
def slow_load(self):
'''
'''
time.sleep(5)
self.file_contents = "Slow load in progress..."
time.sleep(5)
return 'Slow load complete'
if __name__ == '__main__':
win = SlowLoad()
win.show_all()
#time.sleep(10)
Gtk.main()
Дополнительно, вы должны допустить, чтобы другой поток завершился до того, как он завершится правильно или проверьте файл file.lock в дочернем потоке.
Редактировать комментарий к адресу: Первоначально я забыл GObject.threads_init()
. Очевидно, когда кнопка срабатывала, для меня была инициализирована резьба. Это замаскировало ошибку для меня.
Обычно поток создает окно в памяти, сразу же запускает другой поток, когда поток завершает обновление кнопки. Я добавил дополнительный сон, прежде чем я даже позвонил в Gtk.main, чтобы убедиться, что полное обновление COULD запустилось до того, как окно было даже рисовано. Я также прокомментировал это, чтобы убедиться, что запуск потока не мешает рисованию окна.
Вот еще один вариант с использованием планировщика ввода-вывода GIO (я никогда раньше не использовал его с Python, но пример ниже, похоже, работает нормально).
from gi.repository import GLib, Gio, GObject
import time
def slow_stuff(job, cancellable, user_data):
print "Slow!"
for i in xrange(5):
print "doing slow stuff..."
time.sleep(0.5)
print "finished doing slow stuff!"
return False # job completed
def main():
GObject.threads_init()
print "Starting..."
Gio.io_scheduler_push_job(slow_stuff, None, GLib.PRIORITY_DEFAULT, None)
print "It's running async..."
GLib.idle_add(ui_stuff)
GLib.MainLoop().run()
def ui_stuff():
print "This is the UI doing stuff..."
time.sleep(1)
return True
if __name__ == '__main__':
main()
Использовать интроспективный API Gio
для чтения файла с его асинхронными методами и при выполнении начального вызова сделать это как тайм-аут с GLib.timeout_add_seconds(3, call_the_gio_stuff)
, где call_the_gio_stuff
- это функция, которая возвращает False
.
Тайм-аут здесь необходимо добавить (может потребоваться другое количество секунд), так как в то время как асинхронные вызовы Gio являются асинхронными, они не являются неблокирующими, что означает, что активность жесткого диска чтения большой файл или большое количество файлов, может привести к блокированному пользовательскому интерфейсу, поскольку пользовательский интерфейс и ввод-вывод все еще находятся в одном и том же (основном) потоке.
Если вы хотите написать свои собственные функции, async и интегрироваться с основным циклом, используя API-интерфейсы ввода-вывода файлов Python, вам нужно будет написать код в виде GObject или передать обратные вызовы или использовать python-defer
, чтобы помочь вам это сделать. Но лучше использовать Gio здесь, так как он может принести вам массу приятных функций, особенно если вы делаете файл открытым / сохраненным в UX.
Вы также можете использовать GLib.idle_add (обратный вызов) для вызова долговременной задачи, когда GLib Mainloop завершает все события с более высоким приоритетом (которые, я считаю, включает в себя создание пользовательского интерфейса).
Я думаю, что это означает, что это сложный способ сделать то, что предложил @mhall.
По сути, у вас есть запуск, затем запустите эту функцию async_call.
Если вы хотите посмотреть, как это работает, вы можете играть с таймером сна и продолжать нажимать кнопку. [Gg]
Исходя из этого , который не является моей работой.
import threading
import time
from gi.repository import Gtk, GObject
# calls f on another thread
def async_call(f, on_done):
if not on_done:
on_done = lambda r, e: None
def do_call():
result = None
error = None
try:
result = f()
except Exception, err:
error = err
GObject.idle_add(lambda: on_done(result, error))
thread = threading.Thread(target = do_call)
thread.start()
class SlowLoad(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
GObject.threads_init()
self.connect("delete-event", Gtk.main_quit)
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
self.file_contents = 'Slow load pending'
async_call(self.slow_load, self.slow_complete)
def on_button_clicked(self, widget):
print self.file_contents
def slow_complete(self, results, errors):
'''
'''
self.file_contents = results
self.button.set_label(self.file_contents)
self.button.show_all()
def slow_load(self):
'''
'''
time.sleep(5)
self.file_contents = "Slow load in progress..."
time.sleep(5)
return 'Slow load complete'
if __name__ == '__main__':
win = SlowLoad()
win.show_all()
#time.sleep(10)
Gtk.main()
Дополнительно, вы должны допустить, чтобы другой поток завершился до того, как он завершится правильно или проверьте файл file.lock в дочернем потоке.
Редактировать комментарий к адресу: Первоначально я забыл GObject.threads_init()
. Очевидно, когда кнопка срабатывала, для меня была инициализирована резьба. Это замаскировало ошибку для меня.
Обычно поток создает окно в памяти, сразу же запускает другой поток, когда поток завершает обновление кнопки. Я добавил дополнительный сон, прежде чем я даже позвонил в Gtk.main, чтобы убедиться, что полное обновление COULD запустилось до того, как окно было даже рисовано. Я также прокомментировал это, чтобы убедиться, что запуск потока не мешает рисованию окна.
Вот еще один вариант с использованием планировщика ввода-вывода GIO (я никогда раньше не использовал его с Python, но пример ниже, похоже, работает нормально).
from gi.repository import GLib, Gio, GObject
import time
def slow_stuff(job, cancellable, user_data):
print "Slow!"
for i in xrange(5):
print "doing slow stuff..."
time.sleep(0.5)
print "finished doing slow stuff!"
return False # job completed
def main():
GObject.threads_init()
print "Starting..."
Gio.io_scheduler_push_job(slow_stuff, None, GLib.PRIORITY_DEFAULT, None)
print "It's running async..."
GLib.idle_add(ui_stuff)
GLib.MainLoop().run()
def ui_stuff():
print "This is the UI doing stuff..."
time.sleep(1)
return True
if __name__ == '__main__':
main()
Вы также можете использовать GLib.idle_add (обратный вызов) для вызова долговременной задачи, когда GLib Mainloop завершает все события с более высоким приоритетом (которые, я считаю, включает в себя создание пользовательского интерфейса).
Я думаю, что это означает, что это сложный способ сделать то, что предложил @mhall.
По сути, у вас есть запуск, затем запустите эту функцию async_call.
Если вы хотите посмотреть, как это работает, вы можете играть с таймером сна и продолжать нажимать кнопку. [Gg]
Исходя из этого , который не является моей работой.
import threading
import time
from gi.repository import Gtk, GObject
# calls f on another thread
def async_call(f, on_done):
if not on_done:
on_done = lambda r, e: None
def do_call():
result = None
error = None
try:
result = f()
except Exception, err:
error = err
GObject.idle_add(lambda: on_done(result, error))
thread = threading.Thread(target = do_call)
thread.start()
class SlowLoad(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
GObject.threads_init()
self.connect("delete-event", Gtk.main_quit)
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
self.file_contents = 'Slow load pending'
async_call(self.slow_load, self.slow_complete)
def on_button_clicked(self, widget):
print self.file_contents
def slow_complete(self, results, errors):
'''
'''
self.file_contents = results
self.button.set_label(self.file_contents)
self.button.show_all()
def slow_load(self):
'''
'''
time.sleep(5)
self.file_contents = "Slow load in progress..."
time.sleep(5)
return 'Slow load complete'
if __name__ == '__main__':
win = SlowLoad()
win.show_all()
#time.sleep(10)
Gtk.main()
Дополнительно, вы должны допустить, чтобы другой поток завершился до того, как он завершится правильно или проверьте файл file.lock в дочернем потоке.
Редактировать комментарий к адресу: Первоначально я забыл GObject.threads_init()
. Очевидно, когда кнопка срабатывала, для меня была инициализирована резьба. Это замаскировало ошибку для меня.
Обычно поток создает окно в памяти, сразу же запускает другой поток, когда поток завершает обновление кнопки. Я добавил дополнительный сон, прежде чем я даже позвонил в Gtk.main, чтобы убедиться, что полное обновление COULD запустилось до того, как окно было даже рисовано. Я также прокомментировал это, чтобы убедиться, что запуск потока не мешает рисованию окна.