Мои извинения заранее за длину вопроса, я не хотел ничего оставлять.
Некоторая справочная информация
Я пытаюсь автоматизировать процесс ввода данных, написав приложение Python, которое использует Windows API для имитации нажатия клавиш, перемещения мыши и манипулирования окнами/элементами управления. Я должен прибегнуть к этому методу, потому что у меня нет (все же) разрешения безопасности, необходимого для прямого доступа к хранилищу данных/базе данных (например, с использованием SQL) или косвенно с помощью более подходящего API. Бюрократия, это боль; -)
Процесс ввода данных включает в себя коррекцию заказов на продажу из-за изменений в доступности статьи. Недоступные предметы либо удаляются из заказа, либо заменяются другим подходящим товаром.
Изначально я хочу, чтобы человек мог следить за процессом автоматического ввода данных, чтобы убедиться, что все идет правильно. Для этого я замедляю действия, с одной стороны, но также информирую пользователя о том, что происходит в настоящее время через закрепленное окно.
Фактический вопрос
Чтобы пользователь мог остановить процесс автоматизации, я регистрирую ключ Pause/Break как горячую клавишу, а в обработчике я хочу приостановить функции автоматизации. Тем не менее, я в настоящее время изо всех сил пытаюсь найти способ правильно приостановить выполнение функций автоматизации. Когда вызывается функция паузы, я хочу, чтобы процесс автоматизации оставался мертвым на своих дорогах, независимо от того, что он делает. Я не хочу, чтобы он даже выполнял еще одно нажатие клавиши.
ОБНОВЛЕНИЕ [23/01]: Я действительно хочу сделать больше, чем просто паузу, я хочу иметь возможность связываться с процессом автоматизации во время его работы и просить его приостановить, пропустить текущий заказ на продажу, полностью отказаться и, возможно, даже больше.
Может ли кто-нибудь показать мне правильный путь (TM), чтобы достичь того, чего я хочу?
Дополнительная информация
Вот пример того, как работает автоматизация (я использую библиотеку pywinauto):
from pywinauto import application
app = application.Application()
app.start_("notepad")
app.Notepad.TypeKeys("abcdef")
ОБНОВЛЕНИЕ [25/01]: После нескольких дней работы над моим приложением я заметил, что я действительно не использую pywinauto, сейчас я использую его только для поиска а затем я напрямую использую SendKeysCtypes.SendKeys
для имитации ввода с клавиатуры и win32api
для имитации ввода мыши.
То, что я обнаружил до сих пор
Вот несколько методов, с которыми я сталкивался до сих пор в поиске ответа:
-
Я мог бы разделить функциональные возможности автоматизации и прослушиватель интерфейса + hotkey в двух отдельных процессах. Позвольте ссылаться на первое как "автомат", а второе - на "менеджера". Затем менеджер может приостановить выполнение автомата, отправив процессу сигнал SIGSTOP и отключив его с помощью сигнала SIGCONT (или эквивалентов Windows через SuspendThread/ResumeThread).
Чтобы иметь возможность обновлять пользовательский интерфейс, автору необходимо будет сообщить менеджеру о его развитии через какой-то механизм IPC.
Минусы:
-
Не будет ли использование SIGSTOP немного суровым? Будет ли он работать нормально? Многие люди, кажется, советуют против этого и даже называют это "опасным".
-
Я обеспокоен тем, что внедрение механизма МПК будет немного сложнее. С другой стороны, я работал с DBus, который не был бы слишком сложным для реализации.
-
-
Второй метод и тот, который, по-видимому, предлагает много людей, включает использование потоков и, по существу, сводится к следующему (упрощенному):
while True: if self.pause: # pause # Do the work...
Однако, делая это таким образом, кажется, что он остановится только после того, как больше не будет работы. Единственный способ, которым я вижу этот метод, будет заключаться в том, чтобы разделить работу (весь процесс автоматизации) на более мелкие рабочие сегменты (т.е. Задачи). Перед тем как приступить к новой задаче, рабочий поток проверит, следует ли приостановить и ждать.
Минусы:
-
Кажется, что реализация для разделения работы на более мелкие сегменты, например, выше, будет очень уродливым кодом (эстетически).
Как я себе это представляю, все утверждения будут преобразованы, чтобы выглядеть примерно так:
queue.put((function, args))
(например,queue.put((app.Notepad.TypeKeys, "abcdef"))
), и у вас будет поток процессов автоматизации, выполняющийся через задачи, и постоянная проверка состояния паузы перед запуском задача. Это просто не может быть прав... -
Программа фактически не останавливается на своих треках, но сначала закончит задачу (пусть и небольшую), прежде чем на самом деле приостанавливается.
-
Достигнутый прогресс
UPDATE [23/01]: Я реализовал версию своего приложения, используя первый метод с помощью упомянутой функциональности SuspendThread/ResumeThread
. Пока это работает очень хорошо, а также позволяет мне писать средства автоматизации так же, как вы пишете любые другие script. Единственный причуд, с которым я столкнулся, это то, что модификаторы клавиатуры (CTRL, ALT, SHIFT) становятся "застрявшими" при паузе. Возможно, что-то, что я могу легко обойти.
Я также написал тест, используя второй метод (потоки и сигналы/передачу сообщений), и реализовал функцию паузы. Тем не менее, это выглядит очень уродливо (оба проверяют флаг паузы и все, что связано с "выполнением работы" ). Поэтому, если кто-нибудь может показать мне пример того, что похоже на второй метод, я был бы признателен.
Связанные вопросы
- Приостановка процесса?
-
Приостановка потока с использованием класса потоковой передачи
Алекс Мартелли опубликовал ответ, сказав:
Нет способа для других потоков принудительно приостанавливать поток (больше, чем для других потоков, чтобы убить этот поток) - целевой поток должен взаимодействовать, иногда проверяя соответствующие "флаги" (потоковое. подходит для случая паузы/отказа).
Затем он ссылался на многопроцессорный модуль и SIGSTOP/SIGCONT.
- Есть ли способ бесконечно приостановить поток?
-
Приостановка процесса в Windows
Ответ на этот вопрос цитирует документацию MSDN относительно SuspendThread:
Эта функция в основном предназначена для использования отладчиками. Он не предназначен для синхронизации потоков. Вызов SuspendThread в потоке, который владеет объектом синхронизации, например мьютексом или критическим сектором, может привести к тупиковой ситуации, если вызывающий поток пытается получить объект синхронизации, принадлежащий приостановленному потоку. Чтобы избежать этой ситуации, поток в приложении, который не является отладчиком, должен сигнализировать о том, что другой поток приостанавливается. Целевая нить должна быть спроектирована так, чтобы следить за этим сигналом и отвечать соответствующим образом.
- Есть ли способ убить поток в Python?
- Как передать исключение между потоками в python