10

I already asked this exact question a year ago. My application uses Python's multiprocessing module, which works fine when run from the command line, but when I package it as an executable using Pyinstaller, the multiple processes spawn as new instances of the original rather than running the function they are supposed to run. The advice given to me last time as well as everywhere else I look is to call multiprocessing.freeze_support() at the beginning of my if __name__ == "__main__": block, which I have been doing this whole time, but I am suddenly running into this issue again for some reason. What else could possibly be causing this?

Update: I have confirmed that the presence of the freeze_support() line does not affect this issue at all. Commenting it or uncommenting it gives the exact same behavior: copies of the main window are opened and sit there doing nothing. Here is the block where it is called, at the extreme end of my main Python module:

if __name__ == '__main__':
    freeze_support()

    # (A bunch of commented-out lines)
    main()
Community
  • 1
  • 1
dpitch40
  • 2,621
  • 7
  • 31
  • 44

3 Answers3

7

I am an idiot. (Well, maybe not, but it was entirely my fault) multiprocessing signals a process that it is a child process by running it with two additional arguments: the flag --multiprocessing-fork and a numerical handle to a pipe from the parent process. multiprocessing.freeze_support checks for the presence of this flag to decide whether to run the function specified for the child process, or the normal program. Anyway, my method of parsing command-line arguments altered sys.argv, which got rid of the flag and caused the child processes to act like new parent processes.

So, the moral of the story is, never alter sys.argv. I switched to use optparse, which complains about the presence of the flag so I had to pass it a filtered list of arguments. Once I did this, the issue vanished.

Krishna
  • 6,107
  • 2
  • 40
  • 43
dpitch40
  • 2,621
  • 7
  • 31
  • 44
  • 3
    Hi I am still having this issue, but I never even touch the sys.argv on my script. Are you able to forward any references so that I can research why it is doing that? – hpca01 Sep 12 '18 at 19:22
2

I have had the same problem but I have solved putting if clauses in the code to avoid every kivy code to run in a new process. For example:

if __name__ == '__main__': # to avoid new window with a new process
    multiprocessing.freeze_support() # support multiprocessing in pyinstaller
    from kivy.lang.builder import Builder
    from kivy.clock import Clock
    from kivy.uix.popup import Popup
    from kivy.uix.textinput import TextInput
    from kivy.uix.scatterlayout import ScatterLayout
    from kivy.graphics.transformation import Matrix
    from kivy.uix.scatter import Scatter
    from kivy.uix.screenmanager import ScreenManager, Screen
    from kivy.properties import BooleanProperty, ListProperty, BoundedNumericProperty, StringProperty, NumericProperty
    from kivy.uix.boxlayout import BoxLayout
    from kivy.app import App
    from kivy.uix.behaviors import ButtonBehavior
    from kivy.uix.image import Image
    from kivy.core.window import Window

Beyond that, all my classes that use kivy have needed to get put inside the same if clause to avoid errors in main program.

My conclusion is some interaction of kivy, multiprocessing and pyinstaller make the new window pop. If running the code direct from python it doesn't show the problem. In my case, I already was using one if clause to import kivy.core.window, and it has worked fine running the code direct from python, but not after pyinstaller, even using freeze_support.

I hope it helps someone.

Randolfo
  • 647
  • 1
  • 8
  • 18
2

Additional gotcha for setup.py style programs that can cause this:

If you are using entrypoints to launch your program, you may need to put multiprocessing.freeze_support() inside main().

Pyinstaller_setuptools for example calls main() directly, skipping all statements in the if __name__ == '__main__': block.

houterl
  • 21
  • 1