Search code examples
pythonmultithreadingpython-multithreading

Thread won't run in background?


When I call my_batch.run_jobs(), my thread does not run in the background. Instead, it runs synchronously by waiting for the method to finish running.

For context, I am calling this method from within a .py file, and the method is within a class. When I run the same functions outside of this file/class, it runs in the background just fine.

# package_name/module_name.py


class BaseModel(Model):
    class Meta:
        database = get_db()


class Batch(BaseModel):

    def run_jobs():
        
        def sleeper():
            sleep(999)
        
        t = threading.Thread(target=sleeper)
        #t.daemon = True #tried with/ without
        t.start()

for example

my_batch = Batch()
my_batch.run_jobs()
#doesn't print until line above finishes
print("in progress")

Solution

  • I updated your code for testing. It seems to run as expected.

    import time, threading
    
    class BaseModel(): pass
    #    class Meta:
    #        database = get_db()
    
    class Batch(BaseModel):
    
        def run_jobs(self):
            
            def sleeper(): # runs in background thread
                for t in range(10):
                   print('<sleeper>', t)
                   time.sleep(.9)
            
            t = threading.Thread(target=sleeper)
            t.start()
            
            # this runs same time as background thread (sleeper)
            for t in range(10):
               print('<rj>', t)
               time.sleep(.8)
                    
    mybatch = Batch()
    mybatch.run_jobs()  # runs in main thread
    
    # this loop runs after run_jobs completes
    for t in range(5):
       print('<main>', t)
       time.sleep(1)
    

    Output

    <sleeper> 0
    <rj> 0
    <rj> 1
    <sleeper> 1
    <rj> 2
    <sleeper> 2
    <rj> 3
    <sleeper> 3
    <rj> 4
    <sleeper> 4
    <rj> 5
    <sleeper> 5
    <rj> 6
    <sleeper> 6
    <rj> 7
    <sleeper> 7
    <rj> 8
    <rj> 9
    <sleeper> 8
    <main> 0
    <sleeper> 9
    <main> 1
    <main> 2
    <main> 3
    <main> 4
    

    --- Update ---

    Here is the same code split into modules:

    -- mike.py

    import time, threading
    
    class BaseModel(): pass
    #    class Meta:
    #        database = get_db()
    
    class Batch(BaseModel):
    
        def run_jobs(self):
            
            def sleeper(): # runs in background thread
                for t in range(10):
                   print('<sleeper>', t)
                   time.sleep(.9)
            
            t = threading.Thread(target=sleeper)
            t.start()
            
            # this runs same time as background thread (sleeper)
            for t in range(10):
               print('<rj>', t)
               time.sleep(.8)
    

    -- threadchk.py (main script)

    import mike
    import time, threading
        
    mybatch = mike.Batch()
    mybatch.run_jobs()  # runs in main thread
    
    # this loop runs after method completes
    for t in range(5):
       print('<main>', t)
       time.sleep(1)
    

    Output is the same as previous run