2016-12-16 2 views
0

Le code suivant fonctionne sans erreurs:fil Python: l'application appelée une interface qui est attelée pour un thread différent

self.sim.create_pnl_results(gui_values, dfs) 

Ce code me donne une erreur:

thread = Thread(target=self.sim.create_pnl_results, args=(gui_values, dfs)) 
thread.start() 

in _ApplyTypes_ self._oleobj_.InvokeTypes(dispid, 0, wFlags, retType, argTypes, *args), 
com_error: (-2147417842, 'The application called an interface that was marshalled for a different thread.', None, None) 

Il semble que les application appelle un objet com quelque part plus bas sur la ligne et parce que je voudrais mettre un gui (QT) sur le dessus, je dois en faire un fil séparé. Comment puis-je éviter le message d'erreur ci-dessus? J'ai lu qu'il est connecté à un problème de Windows. Toutes les suggestions pour le résoudre en python seraient appréciées. Je n'ai aucun contrôle sur les objets com qui sont appelés depuis l'application et je ne vois pas pourquoi cela ferait une différence si je les appelais depuis le thread principal d'un nouveau thread.

plus d'informations sur l'objet com est appelé:

def process_ts(*args): 
    ts_id, i, dfn , ts_queue = args 
    pythoncom.CoInitialize() 
    ts = win32com.client.Dispatch(pythoncom.CoGetInterfaceAndReleaseStream(ts_id, pythoncom.IID_IDispatch)) 
    ts_queue.put(tuple([i , ACRF._com_to_ts(ts, i, dfn)])) 
    pythoncom.CoUninitialize() 

Répondre

0

beaucoup (sinon la plupart) des applications GUI rencontrer des problèmes si vous essayez de mettre à jour/redessiner l'interface utilisateur d'un autre fil. Imaginez ce qui se passerait si vous aviez un thread essayant d'écrire "blue" 100x dans un fichier, et un autre thread essayant d'écrire "red" 100x. Vous verrez quelque chose comme:

redblueredblruede... 

(accordé avec Python vous avez le GIL donc vous pourriez ne pas obtenir exactement le même effet, mais en utilisant multitraitement vous pourriez probablement y arriver).

La même chose arriverait à votre application graphique si un thread essayait de transformer une région en bleu, tandis que l'autre essayait de l'allumer en rouge. Parce que ce n'est pas souhaitable, il y a des gardes mis en place pour l'empêcher de se produire en lançant des exceptions comme celle que vous avez rencontrée.

Ce que vous avez qui se passe ici est quelque chose comme ceci:

----(UI Thread)-,-----------------> 
       \ 
        `---(new thread)-----(affect the UI)-X kaboom! 

Ce que vous voulez qu'il se passe est quelque chose comme ceci:

----(UI Thread)-,--------------------------------------,---(affect the UI)--> 
       \         /
        `---(new thread)-----(pass result)-` 

Les mécanismes exacts de celui-ci changera de cadre au cadre. Dans .NET, vous avez un if (thing.InvokeRequired){ thing.BeginInvoke(data); }

Sous Windows, les objets COM sont protégés de la même manière. Si vous créez un objet COM sur un thread, il n'aime pas que vous essayiez d'y accéder sur un thread différent. Donc, si vous le créez sur un thread différent et que vous avez toujours besoin d'interagir avec lui, vous devrez communiquer à travers vos threads.

Si votre code ne bloque pas, ou si l'exécution ne prend pas beaucoup de temps (c'est-à-dire < 250ms), l'exécution des appels sur le thread principal devrait être correcte. Typiquement, les frameworks d'interface utilisateur vous permettent d'enregistrer un rappel à exécuter après N fois, puis il sera simplement exécuté sur le thread principal chaque fois que cela peut être.

+0

Il semblerait que ce n'est pas l'interface graphique qui cause le problème, c'est l'interface com qui est initialisée par un thread et je ne peux pas y accéder à partir d'un thread séparé. Je n'ai pas encore trouvé comment transférer au mieux l''appartement' vers le nouveau fil – Nickpick

+0

Si vous ne pouvez pas transférer la chose à un nouveau fil, ce qui semble probable, je vais créer une sorte d'interface de wrapper agréable qui vous permet de faites votre communication, si l'interface existante est maladroitecréer un adaptateur pour la chose que vous essayez d'utiliser) –

+0

Le problème est que l'interface com est initialisée avec une importation au début du programme. J'ai ensuite besoin de définir des valeurs avec un bouton dans l'interface graphique et de calculer une sortie avec un autre bouton, donc de manière inhérente les deux boutons créeraient de nouveaux threads. Je n'ai pas vraiment trouvé de moyen de créer un adaptateur pour le moment. – Nickpick