Как запускать асинхронные задачи в приложениях Python GObject Introspection

Да, вы можете! Это называется sshfs.

Основная идея:

Установить sshfs
sudo apt install sshfs
Установить удаленный каталог
sshfs user@host:/path/to/remote /path/to/local/mount/point

Теперь у вас есть пульт дистанционного управления каталог /path/to/remote доступен в /path/to/local/mount/point.

16
задан 28 May 2012 в 04:13

38 ответов

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

Поскольку это так часто, существует также 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.

15
ответ дан 25 May 2018 в 10:55
  • 1
    Благодаря! Я собираюсь принять ваш ответ, поскольку он указывает мне очень подробно, почему это невозможно. К сожалению, я не могу использовать программное обеспечение, которое не было упаковано для Ubuntu 12.04 в моем приложении (это для Quantal, хотя launchpad.net/ubuntu/+source/python-concurrent.futures ), поэтому я думаю, что я «Я застрял, не выполняя свою задачу асинхронно. Что касается заметки для обсуждения с разработчиками Software Center, я нахожусь в том же положении, что и любой доброволец, чтобы внести изменения в код и документацию или поговорить с ними :-) – David Planella 28 May 2012 в 17:31
  • 2
    GIL выпускается во время ввода-вывода, поэтому отлично использовать потоки. Хотя это не обязательно, если используется async IO. – jfs 10 September 2012 в 11:58

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

. Поскольку это так распространено, 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)

Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:

  1. Большинство реализаций на Python имеют GIL, что делает потоки не полностью задействованы в multicores. Итак: не используйте потоки с python!
  2. Объекты, которые вы хотите вернуть в slow_load из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра!
  3. Библиотека, которую вы вызываете (softwarecenter.db), не является потокобезопасной (кажется, включает в себя gtk или аналогичную), поэтому вызов этих методов в потоке приводит к странному поведению (в моем тест, все от «он работает» над «дампом ядра» до простого выхода без результатов). Итак: нет нитей с программным центром.
  4. Каждый асинхронный обратный вызов в gtk не должен делать ничего, кроме того, что он будет отсылать обратный вызов, который будет вызываться в glib mainloop. Итак: no print, никаких изменений состояния gtk, кроме добавления обратного вызова!
  5. Gtk и, похоже, не работает с потоками из коробки. Вам нужно сделать threads_init, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter(), gtk.gdk.threads_leave(). См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).

Я могу дать вам следующее предложение:

  1. Перепишите slow_load, чтобы возвращать собранные результаты и использовать фьючерсы с процессами.
  2. Переключиться с softwarecenter на python-apt или аналогично (вам, вероятно, это не нравится). Но так как вы наняли Canonical, вы можете попросить разработчиков программного обеспечения напрямую добавить документацию к своему программному обеспечению (например, заявив, что он не является потокобезопасным) и даже лучше, что делает программный центр поточным.

As примечание: решения, заданные другими (Gio.io_scheduler_push_job, async_call), работают с time.sleep, но не с softwarecenter.db. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter.

15
ответ дан 25 July 2018 в 18:45

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

. Поскольку это так распространено, 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)

Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:

  1. Большинство реализаций на Python имеют GIL, что делает потоки не полностью задействованы в multicores. Итак: не используйте потоки с python!
  2. Объекты, которые вы хотите вернуть в slow_load из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра!
  3. Библиотека, которую вы вызываете (softwarecenter.db), не является потокобезопасной (кажется, включает в себя gtk или аналогичную), поэтому вызов этих методов в потоке приводит к странному поведению (в моем тест, все от «он работает» над «дампом ядра» до простого выхода без результатов). Итак: нет нитей с программным центром.
  4. Каждый асинхронный обратный вызов в gtk не должен делать ничего, кроме того, что он будет отсылать обратный вызов, который будет вызываться в glib mainloop. Итак: no print, никаких изменений состояния gtk, кроме добавления обратного вызова!
  5. Gtk и, похоже, не работает с потоками из коробки. Вам нужно сделать threads_init, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter(), gtk.gdk.threads_leave(). См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).

Я могу дать вам следующее предложение:

  1. Перепишите slow_load, чтобы возвращать собранные результаты и использовать фьючерсы с процессами.
  2. Переключиться с softwarecenter на python-apt или аналогично (вам, вероятно, это не нравится). Но так как вы наняли Canonical, вы можете попросить разработчиков программного обеспечения напрямую добавить документацию к своему программному обеспечению (например, заявив, что он не является потокобезопасным) и даже лучше, что делает программный центр поточным.

As примечание: решения, заданные другими (Gio.io_scheduler_push_job, async_call), работают с time.sleep, но не с softwarecenter.db. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter.

15
ответ дан 31 July 2018 в 10:39

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

. Поскольку это так распространено, 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)

Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:

  1. Большинство реализаций на Python имеют GIL, что делает потоки не полностью задействованы в multicores. Итак: не используйте потоки с python!
  2. Объекты, которые вы хотите вернуть в slow_load из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра!
  3. Библиотека, которую вы вызываете (softwarecenter.db), не является потокобезопасной (кажется, включает в себя gtk или аналогичную), поэтому вызов этих методов в потоке приводит к странному поведению (в моем тест, все от «он работает» над «дампом ядра» до простого выхода без результатов). Итак: нет нитей с программным центром.
  4. Каждый асинхронный обратный вызов в gtk не должен делать ничего, кроме того, что он будет отсылать обратный вызов, который будет вызываться в glib mainloop. Итак: no print, никаких изменений состояния gtk, кроме добавления обратного вызова!
  5. Gtk и, похоже, не работает с потоками из коробки. Вам нужно сделать threads_init, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter(), gtk.gdk.threads_leave(). См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).

Я могу дать вам следующее предложение:

  1. Перепишите slow_load, чтобы возвращать собранные результаты и использовать фьючерсы с процессами.
  2. Переключиться с softwarecenter на python-apt или аналогично (вам, вероятно, это не нравится). Но так как вы наняли Canonical, вы можете попросить разработчиков программного обеспечения напрямую добавить документацию к своему программному обеспечению (например, заявив, что он не является потокобезопасным) и даже лучше, что делает программный центр поточным.

As примечание: решения, заданные другими (Gio.io_scheduler_push_job, async_call), работают с time.sleep, но не с softwarecenter.db. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter.

15
ответ дан 4 August 2018 в 16:24

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

. Поскольку это так распространено, 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)

Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:

  1. Большинство реализаций на Python имеют GIL, что делает потоки не полностью задействованы в multicores. Итак: не используйте потоки с python!
  2. Объекты, которые вы хотите вернуть в slow_load из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра!
  3. Библиотека, которую вы вызываете (softwarecenter.db), не является потокобезопасной (кажется, включает в себя gtk или аналогичную), поэтому вызов этих методов в потоке приводит к странному поведению (в моем тест, все от «он работает» над «дампом ядра» до простого выхода без результатов). Итак: нет нитей с программным центром.
  4. Каждый асинхронный обратный вызов в gtk не должен делать ничего, кроме того, что он будет отсылать обратный вызов, который будет вызываться в glib mainloop. Итак: no print, никаких изменений состояния gtk, кроме добавления обратного вызова!
  5. Gtk и, похоже, не работает с потоками из коробки. Вам нужно сделать threads_init, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter(), gtk.gdk.threads_leave(). См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).

Я могу дать вам следующее предложение:

  1. Перепишите slow_load, чтобы возвращать собранные результаты и использовать фьючерсы с процессами.
  2. Переключиться с softwarecenter на python-apt или аналогично (вам, вероятно, это не нравится). Но так как вы наняли Canonical, вы можете попросить разработчиков программного обеспечения напрямую добавить документацию к своему программному обеспечению (например, заявив, что он не является потокобезопасным) и даже лучше, что делает программный центр поточным.

As примечание: решения, заданные другими (Gio.io_scheduler_push_job, async_call), работают с time.sleep, но не с softwarecenter.db. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter.

15
ответ дан 6 August 2018 в 01:03

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

. Поскольку это так распространено, 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)

Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:

  1. Большинство реализаций на Python имеют GIL, что делает потоки не полностью задействованы в multicores. Итак: не используйте потоки с python!
  2. Объекты, которые вы хотите вернуть в slow_load из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра!
  3. Библиотека, которую вы вызываете (softwarecenter.db), не является потокобезопасной (кажется, включает в себя gtk или аналогичную), поэтому вызов этих методов в потоке приводит к странному поведению (в моем тест, все от «он работает» над «дампом ядра» до простого выхода без результатов). Итак: нет нитей с программным центром.
  4. Каждый асинхронный обратный вызов в gtk не должен делать ничего, кроме того, что он будет отсылать обратный вызов, который будет вызываться в glib mainloop. Итак: no print, никаких изменений состояния gtk, кроме добавления обратного вызова!
  5. Gtk и, похоже, не работает с потоками из коробки. Вам нужно сделать threads_init, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter(), gtk.gdk.threads_leave(). См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).

Я могу дать вам следующее предложение:

  1. Перепишите slow_load, чтобы возвращать собранные результаты и использовать фьючерсы с процессами.
  2. Переключиться с softwarecenter на python-apt или аналогично (вам, вероятно, это не нравится). Но так как вы наняли Canonical, вы можете попросить разработчиков программного обеспечения напрямую добавить документацию к своему программному обеспечению (например, заявив, что он не является потокобезопасным) и даже лучше, что делает программный центр поточным.

As примечание: решения, заданные другими (Gio.io_scheduler_push_job, async_call), работают с time.sleep, но не с softwarecenter.db. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter.

15
ответ дан 7 August 2018 в 18:30

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

. Поскольку это так распространено, 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)

Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:

  1. Большинство реализаций на Python имеют GIL, что делает потоки не полностью задействованы в multicores. Итак: не используйте потоки с python!
  2. Объекты, которые вы хотите вернуть в slow_load из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра!
  3. Библиотека, которую вы вызываете (softwarecenter.db), не является потокобезопасной (кажется, включает в себя gtk или аналогичную), поэтому вызов этих методов в потоке приводит к странному поведению (в моем тест, все от «он работает» над «дампом ядра» до простого выхода без результатов). Итак: нет нитей с программным центром.
  4. Каждый асинхронный обратный вызов в gtk не должен делать ничего, кроме того, что он будет отсылать обратный вызов, который будет вызываться в glib mainloop. Итак: no print, никаких изменений состояния gtk, кроме добавления обратного вызова!
  5. Gtk и, похоже, не работает с потоками из коробки. Вам нужно сделать threads_init, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter(), gtk.gdk.threads_leave(). См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).

Я могу дать вам следующее предложение:

  1. Перепишите slow_load, чтобы возвращать собранные результаты и использовать фьючерсы с процессами.
  2. Переключиться с softwarecenter на python-apt или аналогично (вам, вероятно, это не нравится). Но так как вы наняли Canonical, вы можете попросить разработчиков программного обеспечения напрямую добавить документацию к своему программному обеспечению (например, заявив, что он не является потокобезопасным) и даже лучше, что делает программный центр поточным.

As примечание: решения, заданные другими (Gio.io_scheduler_push_job, async_call), работают с time.sleep, но не с softwarecenter.db. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter.

15
ответ дан 10 August 2018 в 07:11

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

. Поскольку это так распространено, 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)

Теперь к вашей проблеме, которая намного сложнее, чем предлагает ваш простой пример. В общем, у вас есть потоки или процессы для решения этой проблемы, но вот почему ваш пример настолько сложный:

  1. Большинство реализаций на Python имеют GIL, что делает потоки не полностью задействованы в multicores. Итак: не используйте потоки с python!
  2. Объекты, которые вы хотите вернуть в slow_load из БД, не подбираются, что означает, что они не могут просто передаваться между процессами. Итак: нет многопроцессорности с результатами программного центра!
  3. Библиотека, которую вы вызываете (softwarecenter.db), не является потокобезопасной (кажется, включает в себя gtk или аналогичную), поэтому вызов этих методов в потоке приводит к странному поведению (в моем тест, все от «он работает» над «дампом ядра» до простого выхода без результатов). Итак: нет нитей с программным центром.
  4. Каждый асинхронный обратный вызов в gtk не должен делать ничего, кроме того, что он будет отсылать обратный вызов, который будет вызываться в glib mainloop. Итак: no print, никаких изменений состояния gtk, кроме добавления обратного вызова!
  5. Gtk и, похоже, не работает с потоками из коробки. Вам нужно сделать threads_init, и если вы вызываете метод gtk или подобный, вы должны защитить этот метод (в более ранних версиях это были gtk.gdk.threads_enter(), gtk.gdk.threads_leave(). См., Например, gstreamer: http: // pygstdocs.berlios.de/pygst-tutorial/playbin.html).

Я могу дать вам следующее предложение:

  1. Перепишите slow_load, чтобы возвращать собранные результаты и использовать фьючерсы с процессами.
  2. Переключиться с softwarecenter на python-apt или аналогично (вам, вероятно, это не нравится). Но так как вы наняли Canonical, вы можете попросить разработчиков программного обеспечения напрямую добавить документацию к своему программному обеспечению (например, заявив, что он не является потокобезопасным) и даже лучше, что делает программный центр поточным.

As примечание: решения, заданные другими (Gio.io_scheduler_push_job, async_call), работают с time.sleep, но не с softwarecenter.db. Это потому, что все это сводится к потокам, процессам и потокам, чтобы не работать с gtk и softwarecenter.

15
ответ дан 15 August 2018 в 19:10
  • 1
    Спасибо! Я собираюсь принять ваш ответ, поскольку он указывает мне очень подробно, почему это невозможно. К сожалению, я не могу использовать программное обеспечение, которое не было упаковано для Ubuntu 12.04 в моем приложении (это для Quantal, хотя launchpad.net/ubuntu/+source/python-concurrent.futures ), поэтому я предполагаю, что я «Я застрял, не выполняя свою задачу асинхронно. Что касается заметки для обсуждения с разработчиками Software Center, я нахожусь в том же положении, что и любой доброволец, чтобы внести изменения в код и документацию или поговорить с ними :-) – David Planella 28 May 2012 в 17:31
  • 2
    GIL выпускается во время ввода-вывода, поэтому отлично использовать потоки. Хотя это не обязательно, если используется async IO. – jfs 10 September 2012 в 11:58

Вот еще один вариант с использованием планировщика ввода-вывода 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()
11
ответ дан 25 May 2018 в 10:55
  • 1
    См. Также GIO.io_scheduler_job_send_to_mainloop (), если вы хотите запустить что-то в основном потоке, как только slow_stuff закончит. – Siegfried Gevatter 27 May 2012 в 21:27
  • 2
    Спасибо Sigfried за ответ и пример. К сожалению, похоже, что с моей текущей задачей у меня нет возможности использовать API Gio, чтобы он выполнялся асинхронно. – David Planella 28 May 2012 в 17:33
  • 3
    Это было действительно полезно, но, насколько я могу судить, Gio.io_scheduler_job_send_to_mainloop не существует в Python :( – sil 19 July 2012 в 03:20

Вы также можете использовать GLib.idle_add (callback) для вызова долговременной задачи после того, как GLib Mainloop завершит все события с более высоким приоритетом (которые, я считаю, включает в себя создание пользовательского интерфейса).

2
ответ дан 25 May 2018 в 10:55
  • 1
    Спасибо, Майк. Да, это определенно поможет при запуске задачи, когда пользовательский интерфейс будет готов. Но, с другой стороны, я понимаю, что когда вызывается callback, это будет выполняться синхронно, таким образом блокируя пользовательский интерфейс, верно? – David Planella 27 May 2012 в 19:08
  • 2
    Idle_add работает не так. Выполнение блокировки вызовов в idle_add по-прежнему является плохим делом, и это предотвратит появление обновлений для пользовательского интерфейса. И даже асинхронный API все еще может блокировать, где единственный способ избежать блокировки пользовательского интерфейса и других задач - сделать это в фоновом потоке. – dobey 27 May 2012 в 19:49
  • 3
    В идеале вы разделили бы свою медленную задачу на куски, так что вы можете запустить ее немного в режиме обратного вызова, вернуть (и позволить другим вещам, например, обратным вызовам пользовательского интерфейса), продолжить выполнение еще одной работы после повторного вызова обратного вызова и так далее на. – Siegfried Gevatter 27 May 2012 в 21:22
  • 4
    Получение с idle_add заключается в том, что возвращаемое значение обратного вызова имеет значение. Если это правда, оно будет вызвано снова. – Flimm 19 April 2013 в 00:20

Использовать интроспективный 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.

2
ответ дан 25 May 2018 в 10:55
  • 1
    Спасибо @dobey. Я на самом деле не читаю файл с диска напрямую, я должен был бы сделать это более ясным в исходном сообщении. Долгое выполнение задачи, которую я запускаю, это чтение базы данных Software Center в соответствии с ответом на askubuntu.com/questions/139032/… , поэтому я не уверен, что могу использовать [ f1] API. Мне было интересно, есть ли способ запускать какую-либо общую долгосрочную задачу асинхронно так же, как это делал GTask. – David Planella 27 May 2012 в 18:57
  • 2
    Я не знаю, что такое GTask, но если вы имеете в виду gtask.sourceforge.net , то я не думаю, что вы должны использовать это. Если это что-то другое, тогда я не знаю, что это. Но похоже, что вам придется взять второй маршрут, о котором я упоминал, и реализовать некоторый асинхронный API для переноса этого кода или просто сделать все это в потоке. – dobey 27 May 2012 в 19:46
  • 3
    В этом вопросе есть ссылка. GTask is (was): chergert.github.com/gtask – David Planella 27 May 2012 в 20:31
  • 4
    Ах, это выглядит очень похоже на API, предоставляемый python-defer (и отложенным API-интерфейсом twisted). Возможно, вам стоит взглянуть на использование python-defer? – dobey 28 May 2012 в 01:31
  • 5
    Вам все равно нужно отложить это вызванное, до тех пор, пока не произойдут основные события приоритета, например, с помощью GLib.idle_add (). Например: pastebin.ubuntu.com/1011660 – dobey 28 May 2012 в 22:44

Я думаю, что это означает, что это сложный способ сделать то, что предложил @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 запустилось до того, как окно было даже рисовано. Я также прокомментировал это, чтобы убедиться, что запуск потока не мешает рисованию окна.

1
ответ дан 25 May 2018 в 10:55
  • 1
    Благодарю. Я не уверен, что смогу это сделать. Во-первых, я ожидал, что slow_load будет запущен вскоре после запуска пользовательского интерфейса, но он, кажется, никогда не будет вызван, если не нажать кнопку, что меня немного смущает, поскольку я думал, что цель кнопки была просто обеспечить визуальную индикацию состояния задачи. – David Planella 27 May 2012 в 20:57
  • 2
    Извините, я пропустил одну строку. Так оно и было. Я забыл сказать GObject, чтобы подготовиться к потокам. – RobotHumans 27 May 2012 в 21:14
  • 3
    Но вы звоните в основной цикл из потока, который может вызвать проблемы, хотя они могут быть не легко раскрыты в вашем тривиальном примере, который не выполняет никакой реальной работы. – dobey 27 May 2012 в 21:53
  • 4
    Действительный момент, но я не думал, что тривиальный пример заслуживает отправки уведомления через DBus (который, как мне кажется, требует нетривиальное приложение) – RobotHumans 27 May 2012 в 21:59
  • 5
    Hm, запуск async_call в этом примере работает для меня, но он приносит хаос, когда я переношу его в свое приложение, и добавляю реальную функцию slow_load, которая у меня есть. – David Planella 28 May 2012 в 04:09

Использовать интроспективный 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.

2
ответ дан 25 July 2018 в 18:45

Вы также можете использовать GLib.idle_add (обратный вызов) для вызова долговременной задачи, когда GLib Mainloop завершает все события с более высоким приоритетом (которые, я считаю, включает в себя создание пользовательского интерфейса).

2
ответ дан 25 July 2018 в 18:45

Вот еще один вариант с использованием планировщика ввода-вывода 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()
11
ответ дан 25 July 2018 в 18:45

Использовать интроспективный 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.

2
ответ дан 31 July 2018 в 10:39

Вы также можете использовать GLib.idle_add (обратный вызов) для вызова долговременной задачи, когда GLib Mainloop завершает все события с более высоким приоритетом (которые, я считаю, включает в себя создание пользовательского интерфейса).

2
ответ дан 31 July 2018 в 10:39

Я думаю, что это означает, что это сложный способ сделать то, что предложил @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 запустилось до того, как окно было даже рисовано. Я также прокомментировал это, чтобы убедиться, что запуск потока не мешает рисованию окна.

1
ответ дан 31 July 2018 в 10:39

Вот еще один вариант с использованием планировщика ввода-вывода 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()
11
ответ дан 31 July 2018 в 10:39

Я думаю, что это означает, что это сложный способ сделать то, что предложил @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 запустилось до того, как окно было даже рисовано. Я также прокомментировал это, чтобы убедиться, что запуск потока не мешает рисованию окна.

1
ответ дан 2 August 2018 в 00:53

Вот еще один вариант с использованием планировщика ввода-вывода 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()
11
ответ дан 2 August 2018 в 00:53

Использовать интроспективный 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.

2
ответ дан 4 August 2018 в 16:24

Я думаю, что это означает, что это сложный способ сделать то, что предложил @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 запустилось до того, как окно было даже рисовано. Я также прокомментировал это, чтобы убедиться, что запуск потока не мешает рисованию окна.

1
ответ дан 4 August 2018 в 16:24

Вот еще один вариант с использованием планировщика ввода-вывода 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()
11
ответ дан 4 August 2018 в 16:24

Использовать интроспективный 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.

2
ответ дан 6 August 2018 в 01:03

Вы также можете использовать GLib.idle_add (обратный вызов) для вызова долговременной задачи, когда GLib Mainloop завершает все события с более высоким приоритетом (которые, я считаю, включает в себя создание пользовательского интерфейса).

2
ответ дан 6 August 2018 в 01:03

Я думаю, что это означает, что это сложный способ сделать то, что предложил @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 запустилось до того, как окно было даже рисовано. Я также прокомментировал это, чтобы убедиться, что запуск потока не мешает рисованию окна.

1
ответ дан 6 August 2018 в 01:03

Вот еще один вариант с использованием планировщика ввода-вывода 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()
11
ответ дан 6 August 2018 в 01:03

Вы также можете использовать GLib.idle_add (обратный вызов) для вызова долговременной задачи, когда GLib Mainloop завершает все события с более высоким приоритетом (которые, я считаю, включает в себя создание пользовательского интерфейса).

2
ответ дан 7 August 2018 в 18:30

Я думаю, что это означает, что это сложный способ сделать то, что предложил @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 запустилось до того, как окно было даже рисовано. Я также прокомментировал это, чтобы убедиться, что запуск потока не мешает рисованию окна.

1
ответ дан 7 August 2018 в 18:30

Другие вопросы по тегам:

Похожие вопросы: