Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pyinstaller executable keeps opening

Background

I am working on face recognition following this link and I would like to build a standalone application using Python. My main.py script looks like the following.

# main.py

# Import packages and other scripts
import tkinter as tk
...

# Some functions
def initialization():
    # OpenCV and sklearn are used here
    ...

def registration():
    # OpenCV, and sklearn are used here
    ...

def face_recognition():
    # OpenCV and sklearn are used here
    ...

# Start the Tkinter GUI
window = tk.Tk()

# Initialize the face recognition model
initialization()

# Input name for registration
tk.Label(window, text = "Name").grid(...)
entry1 = tk.Entry(window)
entry1.grid(row=0, column=1)

# When the button is clicked, different command is executed
tk.Button(window, text='Registration', command=registeration).grid(...) 
tk.Button(window, text='Face Recognition', command=face_recognition).grid(...)

window.mainloop()

Using python interpret to run the script (python main.py), everything works fine.


Problem

I use Pyinstaller to convert the scripts to a single exe with this command:

pyinstaller --onefile \
            --windowed \
            --hidden-import sklearn.neighbors.typedefs \
            main.py

Then, I have two exe generated. The first one is in dist/main and the second one is in dist/main.app/Contents/MacOS/main

When running the exe, the exe keeps duplicate itself. I display the running process and found this result

$ ps
PID    TTY    TIME    CMD
...    ...    ...     /path/to/main -B -s -S -E -c from multiprocessing.semaphore_tracker import main:main(8)
...    ...    ...     /path/to/main -B -s -S -E -c from multiprocessing.semaphore_tracker import main:main(8)
...    ...    ...     /path/to/main -B -s -S -E -c from multiprocessing.semaphore_tracker import main:main(7)
...    ...    ...     /path/to/main -B -s -S -E -c from multiprocessing.semaphore_tracker import main:main(7)
...    ...    ...     /path/to/main -B -s -S -E -c from multiprocessing.semaphore_tracker import main:main(8)

I have no idea what happens to the exe since I do not import multiprocessing packages in my scripts. Any idea how to fix this problem? Thanks


Update 1

I added a --log-level ERROR when using Pyinstaller and gives this result. Not sure if it is related to my problem.

Traceback (most recent call last):
  File "<string>", line 2, in <module>
ModuleNotFoundError: No module named 'Crypto.Math'
174598 INFO: MKL libraries found when importing numpy. Adding MKL to binaries
176282 ERROR: Can not find path ./libtbb.dylib (needed by /Users/user/anaconda3/lib/libmkl_tbb_thread.dylib)

Update 2

I found out that one of the packages that I am using -- imultis VideoStream involves threading. I guess it is the reason for observing from multiprocessing.semaphore_tracker as shown above even though I do not import multiprocessing explicitly.

Then I come across with this post, suggesting to add multiprocessing.freeze_support(). It can suppress the GUI window from keep duplicating, but the background processes as shown using $ ps still keep duplicating. The problem has not fixed yet.


Update 3 (Issue located but not fix)

After debugging the code for quite a while, it turns out that the causes of this infinite looping is NOT due to the threading of imultis VideoStream (I write another script to test imultis and it is completely OK). But the problem comes from importing sklearn!!! This problem has been reported in GitHub in this link.

This GitHub link also suggest to include multiprocessing.freeze_support(). Moreover one of the responses suggests to import sklearn after multiprocessing.freeze_support() is called. I try it with a simple script but the problem is still here.

Conclusion: sklearn causes the executable keeps opening. But I have no idea why it is the case, and I do not know how to solve it. Any help would be appreciated. Thanks.

like image 639
K_inverse Avatar asked Feb 13 '19 04:02

K_inverse


2 Answers

This answer does a good job explaining why this happens: https://stackoverflow.com/a/55382641/109525

First try setting this before starting your program:

export JOBLIB_MULTIPROCESSING=0

If it works, you can add a runtime hook to your program to set the environment variable automatically. See: https://pythonhosted.org/PyInstaller/when-things-go-wrong.html#changing-runtime-behavior

like image 193
0x26res Avatar answered Sep 23 '22 12:09

0x26res


Starting my main entry point with:

from multiprocessing import freeze_support
freeze_support()

Worked for me!

like image 37
user3394381 Avatar answered Sep 25 '22 12:09

user3394381