Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to avoid global in python threads when sharing resources?

I am trying to build a program in python that relies on multiple threads, with data shared between the threads. I am trying to avoid doing this with the global keyword, but not getting anywhere so far.

As a simple example (code below), my main() function spawns one thread, thread1, which should be able to access the variable count, in this case just to print it. At the same time, main() iterates this variable, and thread1 should be able to see count changing. Some self contained code here:

import threading
import time

class myThread (threading.Thread):

    def __init__(self, threadID):
        self.threadID = threadID
        threading.Thread.__init__(self)

    def run(self):
        global count
        for i in range(10):
            print "count is now: ", count, " for thread ", self.threadID, "\n"
            time.sleep(5)


def main():

    global count
    count = 0

    # spawn one or more threads
    thread1 = myThread(1)
    thread1.start()

    for i in range(20):
        time.sleep(2)
        count = count + 1

    # wait for thread1 to finish
    thread1.join()

main()

When reading about threads in python, I haven't found any other ways to do this than using global. However, when reading about global, most people say you should very rarely use it, for good reasons, and some people even think it should be removed from python altogether. So I am wondering if there is actually an alternative way of getting thread1 to "passively" detect that main() has iterated count, and access that new value? E.g. I don't know much about python and pointers (do they even exist in python?), but I would in any case assume this is exactly what global achieves.

Ideally I would be able to call a thread1 method from main() to set a new self.count whenever count is iterated, but as thread1 has a run() method that is blocking I can't see how to do this without having another independent thread inside thread1, which seems too complicated.

like image 391
funklute Avatar asked Dec 09 '25 06:12

funklute


1 Answers

You can create the thread object and fill the class attributes.

import threading
class MyThreadClass(threading.Thread):
  def __init__(self, fruits):
    threading.Thread.__init__(self)
    self.fruits = fruits    

  def run(self):
    self.fruits.append('banana')  

list_fruit = ['apple', 'orange']    
print 'BEFORE:', list_fruit
thread = MyThreadClass(list_fruit)
thread.start() 
thread.join() #Wait for the thread to finish
print 'AFTER:', list_fruit

Output:

BEFORE: ['apple', 'orange']
AFTER: ['apple', 'orange', 'banana']

For your case, you can try:

import threading
import time

class myThread (threading.Thread):

    def __init__(self, threadID):
        self.threadID = threadID
        self.count = 0
        threading.Thread.__init__(self)

    def run(self):
        for i in range(10):
            print "count is now: ", self.count, " for thread ", self.threadID, "\n"
            time.sleep(5)


def main():    
    # spawn one or more threads
    thread1 = myThread(1)
    thread1.start()

    for i in range(20):
        time.sleep(2)
        thread1.count = thread1.count + 1

    # wait for thread1 to finish
    thread1.join()
    print thread1.count

main()

If you want to use the same count shared between multiple thread, you can put your count in an list containing just one element. This way, when assigning count to thread attribute, it will not be a hard copy.

like image 80
Omar Avatar answered Dec 10 '25 19:12

Omar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!