7

これはhttps://stackoverflow.com/questions/37684111/ironpython-exe-file-closing-immediately-no-exception-thrownへのフォローアップです

スレッド ライブラリの Timer オブジェクトの問題が原因で、一度コンパイルするとプログラムが動作しないことがわかりました。ライブラリを \Lib\site-packages ディレクトリに含め、そのディレクトリをプログラムのパスに追加しました。これが私が使用しているテストコードです-単純なカウントプログラムです:

import sys
from threading import Timer

sys.path.append('C:\Users\[user]\Documents\Visual Studio 2015\Projects\Testing Timer Compilation issue\Testing Timer Compilation issue')
sys.path.append('C:\Users\[user]\Documents\Visual Studio 2015\Projects\Testing Timer Compilation issue\Testing Timer Compilation issue\Lib')

class Chron():
    def __init__(self):
        self.t = Timer(2, self.count)
        self.t.start()
        self.i = 0

    def count(self):
        print(self.i)
        self.i += 1
        if self.i <= 15:
            self.t = Timer(2, self.count)
            self.t.start()

c = Chron()

Visual Studio 内の Interactive Interpreter で完全に動作しますが、pyc.py を使用して exe ファイルにコンパイルすると、実行されず、〜 5 秒後に単に閉じられ、例外はスローされません。

前の質問で述べたように、ソース コードに機密性の高い資格情報が含まれているため、コンパイルする必要がある Timer を含むプログラムがあります。タイマーをexe内で動作させるために必要なトリックはありますか? それは単に互換性がありませんか?

編集:回答なしで6日間。残念ながら、インターネット上のどこにも、この特定の問題に関するリソースはないようです。この問題を抱えているのは私だけのようです。問題は Timer オブジェクト自体にあるように思われるため、これは奇妙に思えます。また、Timer を含むアプリケーションをデプロイしようとした人が他にいないとは思えません。私は完全に困惑しているので、この時点でどんな洞察も役に立ちます。

4

1 に答える 1

5

問題は、実行可能ファイルのメイン スレッドが終了したものの、実行中の他のスレッドがいくつかあるはずのケースを適切に処理するために、基になる Python インタープリターに依存していることです。

CPython または IronPython を使用してコードを直接実行すると、期待どおりに動作します。作成する Timer オブジェクトは、実際には Thread の特殊化です。インタープリターは、デーモン以外のスレッドがまだアクティブであることを認識し、終了しません。2 種類のスレッドの違いがわからない場合は、デーモン スレッドの説明についてドキュメントを参照してください。

ただし、実行可能ファイルとして実行すると、IronPython がインタープリターをラップするために使用するコードはそれほど親切ではないように見えます。メインスレッドが終了するのを待ってから、すべてを閉じます。これは、タイマーが非デーモン スレッドであると宣言されているにもかかわらず発生します。おそらく、これは IronPython のバグです。

したがって、解決策は、Timer スレッドがまだ動作している間、メイン スレッドを実行したままにすることです。このサンプル コードでこれを行う最も簡単な方法は、単にスリープすることです。たとえば、次のようにします。

import sys
sys.path.append(r"c:\Program Files (x86)\IronPython 2.7\Lib")
from threading import Timer
from time import sleep

class Chron():
    def __init__(self):
        self.t = Timer(2, self.count)
        self.t.start()
        self.i = 0

    def count(self):
        print(self.i)
        self.i += 1
        if self.i <= 15:
            self.t = Timer(2, self.count)
            self.t.start()

c = Chron()
sleep(35)

ただし、より複雑なアプリケーションの場合は、スレッド間の通信を考慮して、いつ閉じるかを調整する必要があります。たとえば、join()を使用してスレッドの終了を待機します。

于 2016-07-07T17:06:30.770 に答える