Skip to content Skip to sidebar Skip to footer

Python - Disable Multiple Py Script Instances And Pass Their Args To Main Instance

For example my py script already has one instance running and when I fire another instance with args, instead of allowing the new instance to run, make it pass its args to the main

Solution 1:

It is possible but not trivial because the processes are unrelated. So you have to set :

  • an exclusion mechanism (file lock should be portable across architectures) to allow a process to know if it is the first - beware of race condition when a server is about to exit when a new process arrives ...
  • the first process opens a listener - a socket on an unused port should be portable
  • you must define a protocol to allow you processes to communicate over the socket
  • when a process discovers it is not the first, it contacts the first over the socket and passes its arguments

So it can work, but it is a lot of work ...

There could be solutions a little simpler if you can limit you to a specific architectur (only Windows or only Linux) and make use of specific libraries, but it will nether be a simple job.

Solution 2:

Yes, something like this is possible. I'm not sure if it's possible to reliably detect if one instance (process) of the application is already running, but one possible way to do this is to reserve a TCP port for the program. The first application that starts will listen on that port and act like the server. Since only process can listen at the same port at the same time, all following processes will fail to create a listen socket and could then act like a client.

You could use a multiprocessing.connection to implement this. The following is a working example to demonstrate the concept:

import multiprocessing.connection
import sys

SERVER_HOST = 'localhost'
SERVER_PORT = 6000

g_total = 0defprocess_numbers(numbers):
    global g_total
    for number in numbers:
        g_total += number
        print('Adding number %d. Total is now %d.' % (number, g_total))


defserver_main(listener, numbers):
    process_numbers(numbers)
    print('Starting server.')
    whileTrue:
        client = listener.accept()
        numbers = list(client.recv())
        client.close()
        ifnot numbers:
            break
        process_numbers(numbers)


defclient_main(numbers):
    client = multiprocessing.connection.Client((SERVER_HOST, SERVER_PORT), 'AF_INET')
    print('Starting client.')
    client.send(numbers)


defmain():
    numbers = map(int, sys.argv[1:])
    try:
        listener = multiprocessing.connection.Listener((SERVER_HOST, SERVER_PORT), 'AF_INET')
    except OSError:
        client_main(numbers)
    else:
        server_main(listener, numbers)

if __name__ == '__main__':
    main()

Assuming you have saved the above code as main.py, calling py main.py 1 2 3 will print the following output:

Adding number 1. Total is now 1.
Adding number 2. Total is now 3.
Adding number 3. Total is now 6.
Starting server.

The application will keep running. Now open a second terminal and run py main.py 4 5 6. The script will only print:

Starting client.

However, your first application (acting as the server) will now print:

Adding number 4. Total is now 10.
Adding number 5. Total is now 15.
Adding number 6. Total is now 21.

If you repeat the command it prints:

Adding number 4. Total is now 25.
Adding number 5. Total is now 30.
Adding number 6. Total is now 36.

and so on. You can quit the server by calling the client without arguments.

NOTE: This answer was written for and tested in Python 3.7, since Python 2.x is already dead. But the multiprocessing.connection also exists in Python 2.7, so I think the code should probably work in Python 2.7 as well (possibly with minor modifications).

Post a Comment for "Python - Disable Multiple Py Script Instances And Pass Their Args To Main Instance"