1

I have been trying to use Threads in python. I am working on a Pi hardware project.

Here's the problem:

When I create a thread, and call it like this, the loop keeps creating new threads before the old ones are completed. Hence, slowing the program down... (printing 'threading.active_count' displays 20+ active threads).

while True:
    t4 = Thread(target = myFunc, args=())
    t4.start()

    print("Hello World")

I need a threading process that runs the same function over and over on a SINGLE thread without affecting or delaying my main program. i.e. when a thread has completed executing the function, run it again... but my main should still be printing "Hello World" as normal.

I've found one way to stop it crashing, which is to sit and "wait" until the thread is finished, and then start again. However, this is a blocking approach, and completely defeats the purpose of threading.

while True:
    t4 = Thread(target = myFunc, args=())
    t4.start()
    t4.join()

    print("Hello World")

Any suggestions?

1
  • 1
    Why don't you just create a thread_func that has a while True: which calls myFunc and then you create t4 = Thread(target = thread_func, args=())? Commented May 18, 2018 at 13:03

4 Answers 4

4

You can use a multiprocessing.pool.ThreadPool to manage both the starting of new threads and limiting the maximum number of them executing concurrently.

from multiprocessing.pool import ThreadPool
from random import randint
import threading
import time

MAX_THREADS = 5  # Number of threads that can run concurrently.
print_lock = threading.Lock()  # Prevent overlapped printing from threads.

def myFunc():
    time.sleep(random.uniform(0, 1))  # Pause a variable amount of time.
    with print_lock:
        print('myFunc')

def test():
    pool = ThreadPool(processes=MAX_THREADS)

    for _ in range(100):  # Submit as many tasks as desired.
        pool.apply_async(myFunc, args=())

    pool.close()  # Done adding tasks.
    pool.join()  # Wait for all tasks to complete.
    print('done')


if __name__ == '__main__':
    test()
Sign up to request clarification or add additional context in comments.

2 Comments

You might change the word "threads" to "tasks" in the comment that says, "Submit as many threads as desired."
@james: One of the dangers of using the multiprocessing module to do threading stuff I suppose. Agreed and changed. Thanks.
1

I need a threading process that runs the same function over and over on a SINGLE thread

This snippet creates a single thread that continually calls myFunc().

def threadMain() : 
    while True :
        myFunc()

t4 = Thread(target = threadMain, args=())
t4.start()

4 Comments

I'm essentially developing on the Pi like it were an embedded system in C with a void(main)... what you are saying will work, but if you put that thread code inside a 'while True:', you will see the problem I am facing...
@embedded.95, I can see the problem that would cause, but I don't see the problem that you are trying to solve. My snippet causes myFunc() to be called "over and over" while the main thread goes off and does something else. How is that different from what you are trying to achieve?
For example... In my main I have an idle state where my code is doing something... playing music for example. During this idle state if I were to perform some kind of input (e.g. pressing a button) I would want to call myFunc like an interrupt to execute whatever is in there. This should not block my main which is playing music the entire time.
@embedded.95, that sounds like a reason to use a thread, not a reason to have a loop that continually creates new threads.
1

Make a delegate thread - i.e. a thread to run your other threads in sequence:

def delegate(*args):
    while True:
        t = Thread(target=myFunc, args=args) # or just call myFunc(*args) instead of a thread
        t.start()
        t.join()

t = Thread(target=delegate, args=())
t.start()
while True:
    print("Hello world!")

Or even better, redesign your myFunc() to run its logic within a while True: ... loop and start the thread only once.

I'd also advise you to add some sort of a delay (e.g. time.sleep()) if you're not performing any work in your threads to help with context switching.

4 Comments

Worked perfectly. Thank you.
Your answer is on the right track, but calling t.join() immediately after calling t.start() never makes any sense. Instead of spawning a new thread to call myFunc and then waiting for the thread to complete, your delegate() function should simply call myFunc.
how could I then use this approach to trigger the thread from my main While loop?
@jameslarge - running a separate thread from within the delegate thread is just a demonstration on how to have myFunc() running in a separate thread while something else runs in the delegate thread, while the main thread is free. If no additional work needs to be performed while myFunc() is running then the delegate should just call myFunc() directly as stated in the comment.
0

setDaemon(True) from threading.Thread class more here https://docs.python.org/2/library/threading.html#threading.Thread.daemon

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.