Search code examples
pythonmultithreadingoopattributesconcurrent.futures

Using class attribute in concurrent.futures threads


How can I use some class attribute within a thread that calls other methods without editing the initial value and without passing the attribute as a parameter?

"First" and "second" value must always be equal to "init" value, and "third" and "fourth" must be both equal.

This example shows the initial problem:

from concurrent.futures import ThreadPoolExecutor
from random import random
from time import sleep

class main():
    def __init__(self):
        self.var = random()
        print('init', self.var)

    def first(self):
        print('first', self.var)
        self.second()
        print('fourth', self.var)

    def second(self):
        print('second', self.var)
        self.var = random()
        print('third', self.var)
        sleep(1)

m = main()
with ThreadPoolExecutor() as executor:
    executor.submit(m.first)
    executor.submit(m.first)
    executor.submit(m.first)

Assigning self.var to another attribute withing the method doesn't obviously work:

class main():
    def __init__(self):
         self.var = random()
         print('init', self.var)

    def first(self):
         self.var2 = self.var
         print('first', self.var2)
         self.second()
         print('fourth', self.var2)

    def second(self):
        print('second', self.var2)
        self.var2 = random()
        print('third', self.var2)
        sleep(1)

The only solution I tried is assigning the attribute to a local variable and passing it to the called function as a parameter. This is not a good solution in my case because I need to pass lots of attributes and the code rapidly increase and begin less readable.

class main():
    def __init__(self):
        self.var = random()
        print('init', self.var)

    def first(self):
        var = self.var
        print('first', var)
        var = self.second(var)
        print('fourth', var)

    def second(self, par):
        print('second', par)
        par = random()
        print('third', par)
        sleep(1)
        return par

Can you think of a pythonic way to use the attribute instead of the local variable passed as parameter?

EDIT: I've just found out a new way to face the problem: using "nonlocal" statement and nesting the functions, what do you think about it?

class main():
def __init__(self):
    self.var = random()
    print('init', self.var)

def first(self):
    var = self.var
    print('first', var)

    def second():
        nonlocal var
        print('second', var)
        var = random()
        print('third', var)
        sleep(1)

    second()
    print('fourth', var)

Solution

  • If you just want to have separate state for each tread, you can create and pass different objects into each thread:

    from concurrent.futures import ThreadPoolExecutor
    from random import random
    from time import sleep
    
    class main():
        def __init__(self):
            self.var = random()
            print('init', self.var)
    
        def first(self):
            print('first', self.var)
            self.second()
            print('fourth', self.var)
    
        def second(self):
            print('second', self.var)
            self.var = random()
            print('third', self.var)
            sleep(1)
    
    def worker():
        m = main()
        m.first()
    
    with ThreadPoolExecutor() as executor:
        executor.submit(worker)
        executor.submit(worker)
        executor.submit(worker)