Using a global list in a Thread object - python

I'm trying to make a simple thread that appends stuff to a global list and then print the results in the main thread after sleeping for a few seconds:
import time,threading
list_of_things = []
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def __run__(self):
global list_of_things
for i in range(0, 10):
list_of_things.append('hello ' + str(i))
if __name__ == "__main__":
mythread = MyThread()
mythread.start()
time.sleep(5)
print list_of_things
The list is apparently empty even though I declared it global in the thread.

Rename your __run__ method to run. And also instead of calling time.sleep(5), you should call .join() on thread to keep the program waiting till thread finishes its job.
import threading
list_of_things = []
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global list_of_things
for i in range(0, 10):
list_of_things.append('hello ' + str(i))
if __name__ == "__main__":
mythread = MyThread()
mythread.start()
mythread.join()
print list_of_things

Related

Write data to multiple files using multiple threads

I want to create multiple file using multiple threads, and append data (after some operation is performed) to corresponding files from their respective threads.
I tried it, but data is getting messed between threads and correct data is not added to respective files.
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
with open('file_'+count+'_logs.txt', 'a+') as result:
result.write("Starting " + self.name)
result.write("Exiting " + self.name)
print ("Starting " + self.name)
print_time(self.name, self.counter, 5)
print ("Exiting " + self.name)
def print_time(threadName, delay, counter):
while counter:
if exitFlag:
threadName.exit()
time.sleep(delay)
print ("%s: %s" % (threadName, time.ctime(time.time())))
counter -= 1
myList = ['string0', 'string1', 'string2', 'string3']
if __name__ == "__main__":
count = 0
for data in myList:
count += 1
mythread = myThread(count, "Thread-" + str(count), count)
mythread.start()
mythread.join()
I expect that 4 files shall be created from 4 threads, and data from thread 1 should be written to file_1_logs.txt and so on...
But while writing data, sometimes all data is written in a single file.
How do I write this data to file correctly?
Don't use higher-scope or global variables in threads. Every variable (that you want to modify) must be local to the thread.
That means you need to pass the initial values of everything to the Thread constructor. The same is true for functions like your print_time. Either everything the function needs to do its job is passed via the arguments – or you turn it into a class method.
Consider the following changes. Note how MyThread is completely self-contained:
from threading import Thread
from time import sleep
from datetime import datetime
class MyThread(Thread):
def __init__(self, threadID, name, delay, data):
Thread.__init__(self)
self.threadID = threadID
self.name = name
self.data = data
self.delay = delay
self.logfile = None
def run(self):
with open('file_%s_logs.txt' % self.threadID, 'a+') as logfile:
self.logfile = logfile
self.log("Starting")
self.print_time(5)
self.log("Exiting")
self.logfile = None
def print_time(self, repeat):
for c in range(repeat):
sleep(self.delay)
self.log(self.data)
def log(self, message):
now = datetime.now().isoformat()
formatted_line = "%s:%s:%s" % (now, self.name, message)
print(formatted_line)
if self.logfile:
self.logfile.write(formatted_line + '\n')
if __name__ == "__main__":
myList = ['string0', 'string1', 'string2', 'string3']
threads = []
# spawn threads
for idx, data in enumerate(myList):
thread = MyThread(idx, "Thread-%s" % idx, idx, data)
threads.append(thread)
thread.start()
# wait for threads to finish
while True:
if any(thread.is_alive() for thread in threads):
sleep(0.1)
else:
print("All done.")
break

Modifying and acessing of variables of a different class by thread in python

Am very much new to python. So what i might be asking may not be correct. What am looking to do is. Create a thread from mainss and start the thread. When the thread is started i want it to access the variable of the mainss class from where thread is created and Modify the variable values. And i want the execution of mainss to sleep until thread modifies one of its variable value. How can i achieve this? Here is the code i tried below. Comment in the code of mythread.py class is where I need to modify the value of count variable of mainss class
main.py
#!/usr/bin/python
import time
from myThread import myThread
class mainss():
def __init__(self):
print "s"
def callThread(self):
global count
count = 1
# Create new threads
thread1 = myThread(1, "Thread-1", 1, count)
thread1.start()
# time.sleep(10) until count value is changed by thread to 3
print "Changed Count value%s " % count
print "Exiting"
m = mainss()
m.callThread()
myThread.py
#!/usr/bin/python
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, counter, count):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
self.count = count
def run(self):
print_time(self.name, 1, 5, self.count)
def print_time(threadName, delay, counter, count):
from main import mainss
while counter:
if exitFlag:
threadName.exit()
time.sleep(delay)
count = count + 1
print "count %s" % (count)
# here i want to modify count of mainss class
counter -= 1
Thanks in advance
Using Multiprocessing, a Manager dictionary is used to communicate between or to processes https://pymotw.com/3/multiprocessing/communication.html#managing-shared-state Note that the Manager dictionary can be changed while the process is running. Multiprocessing also has a wait feature https://pymotw.com/3/multiprocessing/communication.html#signaling-between-processes
I would use a threading.Event and a Queue
Something like this, (Please note that i didn't test this myself and obviously you gonna have to make some changes.)
main.py
import Queue
import threading
from myThread import myThread
class mainss:
def __init__(self):
self.queue = Queue.Queue()
self.event = threading.Event()
def callThread(self):
self.queue.put(1) # Put a value in the queue
t = myThread(self.queue, self.event)
t.start()
self.event.wait() # Wait for the value to update
count = self.queue.get()
print "Changed Count value %s" % count
if __name__ == '__main__':
m = mainss()
m.callThread()
myThread.py
import threading
class myThread(threading.Thread):
def __init__(self, queue, event):
super(myThread, self).__init__()
self.queue = queue
self.event = event
def run(self):
while True:
count = self.queue.get() # Get the value (1)
count += 1
print "count %s" % (count)
self.queue.put(count) # Put updated value
self.event.set() # Notify main thread
break

PySide: Threads destroyed whie still running

I'm having problem with QThreads in python.
I would like to start my multi QThread when I push on button Run.
But the compiler outputs following error:
"QThread: Destroyed while thread is still running"
I don't know what is wrong with my code.
Any help would be appreciated.
Here is my code:
# -*- coding: utf-8 -*-
from PySide import QtCore, QtGui
from Ui_MainWindow import Ui_MainWindow
from queue import Queue
import sys, re, random
import time, random, re, urllib.request
from urllib.parse import urljoin
class Worker(QtCore.QThread):
def __init__(self,threadID, name, q, delay):
QtCore.QThread.__init__(self)
self.threadID = threadID
self.name = name
self.q = q
self.delay = delay
self._running = False
def run(self):
self._running = True
print ("start - %s" %self.name)
while self._running:
req = self.request(self.name, self.q, self.delay)
def stop(self, wait=False):
print (self.name)
self._running = False
def request(self, threadName, q1, delay):
while not self.q.empty():
time.sleep(delay)
q = q1.get()
print ("%s: %s %s %s" % (threadName, time.ctime(time.time()), q, delay))
if self.q.empty():
print ("queue empty")
self.stop()
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.backend = Queue()
self.connect(self.ui.actionStart, QtCore.SIGNAL('triggered()'),self.start)
def start(self):
try :
f1 = open('./payload/backend.log')
except FileNotFoundError as e:
return
threadList = ["Thread-1", "Thread-2", "Thread-3", "Thread-4", "Thread-5"]
self.url = "http://test.com"
self.threads = []
threadID = 1
for payload in f1.read().splitlines() :
full_url = urljoin(self.url, payload)
self.backend_dir.put(full_url)
for tName in threadList:
ran_int = random.randint(1, 2)
downloader = Worker(threadID, tName, self.backend, ran_int)
downloader.start()
self.threads.append(downloader)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
log
QThread: Destroyed while thread is still running
QThread: Destroyed while thread is still running
QThread: Destroyed while thread is still running
QThread: Destroyed while thread is still running
You are trying to do something that is a built-in of Qt: a QThreadPool.
I would advice you to read the doc and use it instead.
If you really want to use QThread:
You should not subclass QThread. Instead you should subclass the basic QObject to create your worker and use the moveToThread method:
class WorkerSignals(QObject):
finished = pyqtSignal()
class Worker(QObject):
def __init__():
self.signal = WorkerSignals()
def run(self):
# Your stuff
print('running')
self.signal.finished.emit()
Then somewhere else:
thread = QThread()
worker = Worker(...)
worker.moveToThread(thread)
thread.started.connect(worker.run)
worker.finished.connect(thread.quit)
worker.finished.connect(worker.deleteLater)
thread.finished(thread.deleteLater)
thread.start()
The solution is a rough translation of this one in C++:
https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
Hope this helps!
The problem is caused by the way you are using the queue.
All the threads start and begin their tasks normally, up until the queue becomes empty. At that point, the first thread to finish terminates, but the other four threads are left waiting for an item to be returned from the queue, which never comes.
This is because you use get with no arguments, which will block indefinitely until an item becomes available. Instead, you should use get_nowait, and also call stop() unconditionally at the end of request():
from queue import Queue, Empty
...
class Worker(QtCore.QThread):
...
def request(self, threadName, q1, delay):
while not q1.empty():
time.sleep(delay)
try:
q = q1.get_nowait()
except Empty:
break
else:
print ("%s: %s %s %s" % (threadName, time.ctime(time.time()), q, delay))
print ("queue empty")
self.stop()
I believe that you need to call self.threads.append(downloader) before downloader.start() so that the thread doesn't go out of scope and get garbage collected.

Why doesn’t this thread terminate?

I am trying to use the python threading module. As I am sysadmin, I struggle a little bit when developing; and this concept is kind of new for me. I launch two threads and I want to stop them, when the main thread sets a flag to False:
class My_Thread( threading.Thread):
def __init__(self, thread_id, thread_name, count):
threading.Thread.__init__(self)
self.thread_id = thread_id
self.thread_name = thread_name
self.count = count
def run(self):
do_job(self.thread_name, self.thread_id, self.count)
def do_job(t_name, t_id, count):
while not get_kill():
print "It is "+str(time.time())+" and I am "+str(t_name)
print get_kill()
time.sleep(count)
kill = False
def get_kill():
return kill
def set_kill(state):
kill = state
if __name__ == '__main__':
a = My_Thread(1, "Thread-1", 2)
b = My_Thread(2, "Thread-2", 1)
a.start()
b.start()
while(True):
try:
pass
except KeyboardInterrupt,ki:
set_kill(True)
sys.exit(0)
But the value is never read as changed in both threads and they don't exit. Why is this value not properly read from threads?
The problem
In set_kill(), you are creating a new local variable kill setting it to state, and returning from the function. You are not actually updating the value of kill in the global scope.
To do that, you would need to have:
def set_kill(state):
global kill
kill = state
A better way
Using globals like that is generally considered bad practice, you probably want to convert your kill variable and functions into an object, to encapsulate that data and behaviour together:
class Kill(object):
kill = False
def get(self):
return self.kill
def set(self, value):
self.kill = value
Which you would use like this:
class MyThread(Thread):
def __init__(self, thread_id, thread_name, count, kill):
self.kill = kill
...
def do_job(self, ...):
while not self.kill.get():
...
if __name__ == '__main__':
kill = Kill()
a = My_Thread(1, "Thread-1", 2, kill)
b = My_Thread(2, "Thread-2", 1, kill)
...
kill.set(True)

override multiprocessing in python

how can i get variable in class which is override multiprocessing in python:
#!/usr/bin/env python
import multiprocessing
import os
class TestMultiprocess(multiprocessing.Process):
def __init__(self):
multiprocessing.Process.__init__(self)
self.myvar = ''
def myfunc(self):
return os.getpid()
def run(self):
self.myvar = self.myfunc()
mlist = []
for i in range(10):
t = TestMultiprocess()
mlist.append(t)
t.start()
for j in mlist:
t.join()
print t.myvar
i can not get value "myvar" from class TestMultiprocess, i just get blank. But i already override the run() function from Process.
sorry if my spell very bad ...
The run() will executed in a separate process; processes don't share memory, normally. multiprocessing does support shared variables, though, through the explicit Value class:
#!/usr/bin/env python
import multiprocessing
import os
class TestMultiprocess(multiprocessing.Process):
def __init__(self):
multiprocessing.Process.__init__(self)
self.myvar = multiprocessing.Value('i',0)
def myfunc(self):
return os.getpid()
def run(self):
self.myvar.value = self.myfunc()
mlist = []
for i in range(10):
t = TestMultiprocess()
mlist.append(t)
t.start()
for j in mlist:
j.join()
print j.myvar.value
replace t with j in the last loop
for j in mlist:
j.join() # t with j
print j.myvar # t with j
EDIT: and this will not solve your problem
by the way if you want to get the process pid you don't have to override the run() method just for that you can just do:
for j in mlist:
j.pid

Categories