Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 days ago.
Improve this question
I wrote async PyQt code that automatically downloads some files from web with few seconds duration like below:
pop async method
def pop(q):
global globalCnt
global globalLabel
while True:
url = q.get()
if url:
webbrowser.get("firefox").open(url)
globalCnt -= 1
globalLabel.setText = str(globalCnt)
time.sleep(3)
PyQT main window class
(Please assume class MyApp(QWidget) exists)
def MyApp(QWidget):
def initUI(self):
global globalLabel
self.setWindowTitle('Hello PyQT')
self.labelLayout = QHBoxLayout()
self.labelLayout.addStretch(1)
self.labelLayout.addWidget( QLabel("### Count of : ") )
self.labelLayout.addWidget( globalLabel )
self.vlayout.addLayout( self.labelLayout )
self.setLayout(self.vlayout)
self.center()
self.show()
def onEnter(self):
global globalLabel
for i in links:
urlStr = "https://foo.bar" + linkstr[front : end-7]
global globalCnt
globalCnt += 1
globalLabel.setText = str(globalCnt)
que.put( urlStr )
self.urlArray.append( urlStr )
Global section
if __name__ == '__main__':
app = QApplication(sys.argv)
globalCnt = 0
globalLabel = QLabel("000")
ex = MyApp()
que = Queue()
thread1 = threading.Thread( target=pop, args=(que, ) )
thread1.daemon = True
thread1.start()
sys.exit(app.exec_())
I defined global label : gloablLabel and I changed globalLabel different each spot
As I think, gloablLabel increases in onEnter event and decreases in pop method,
but it remains the default value 000.
How can I fix it?
Related
This question already has answers here:
How to share a variable between 2 threads
(1 answer)
What is the use of join() in threading?
(12 answers)
Closed 1 year ago.
I have a while True loop that needs to be run in the background to update a variable and a function that needs to return that same variable.
I tried this as a test:
import threading
downspeed = 0
def updating():
while True:
downspeed = downspeed+1
def main():
while True:
print(downspeed)
u = threading.Thread(name='background', target=updating)
m = threading.Thread(name='foreground', target=main)
u.start()
m.start()
But it only returns 0
Your code is not really a sufficient test. The test ought to include:
Allowing some time for the threads to run to see what they do.
Make the threads sleep, at least for a little time, to allow task switches to occur.
See this code:
import threading
import time
can_run = True
downspeed = 0
def updating():
global downspeed
while can_run:
downspeed = downspeed+1
time.sleep(0.1) # Allow taskswitches
def main():
while can_run:
print(downspeed)
time.sleep(1) # Allow taskswitches
u = threading.Thread(name='background', target=updating)
m = threading.Thread(name='foreground', target=main)
u.start()
m.start()
time.sleep(10) # Allow time for the threads to do what they want
can_run = False
print('Done')
u.join()
m.join()
There are no problems sharing variables in python because of the GIL. Although this only makes changes atomic.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
Somehow this is frying my brain, i dont know how to get the function to start again after they are done. The goal is to run them at the same time and when theyre finished they should start again:
if __name__ == '__main__':
current_task += 1
Thread(target = main).start()
current_task += 1
Thread(target = main).start()
pass
You could use a while loop within main:
import threading
import time
def main():
while 1:
print("starting")
time.sleep(2)
print("done")
if __name__ == '__main__':
threading.Thread(target=main).start()
Out:
starting
done
starting
done
starting
...
You could start a new thread at the end of your main-method:
def main():
# .. do some stuff ..
Thread(target=main).start()
if __name__ == '__main__':
current_task += 1
Thread(target = main).start()
current_task += 1
Thread(target = main).start()
pass
This way, both threads spawn a new thread with a new execution once they are done.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
What I was wondering is if it's possible to put a timer in my program so that like every 1 min. the program will update a list box with data?
class App():
def __init__(self):
self.root = tk.Tk()
self.label = Label(text="")
self.label.pack()
self.update_clock()
self.root.mainloop()
def update_clock(self):
now = time.strftime("%H:%M:%S")
self.label.configure(text=now)
# Put Arrivals in box===============================================================
arrivallb.delete(0, END)
now = dt.datetime.now()
dte = now.strftime("%m-%d-%Y")
conn = sqlite3.connect('reservation.db')
c = conn.cursor()
c.execute("SELECT * FROM reserve")
records = c.fetchall()
for record in records:
if record[22] != "*":
if record[8] == dte:
arrivallb.insert(0, str(record[13]) + " " + record[0] + ", " + record[1])
self.root.after(10000, self.update_clock)
app=App()
I figured it out. Below is the code that updates my list box. Thanks everyone for your input.
class App():
def __init__(self):
self.root = tk.Tk()
self.label = Label(text="")
self.label.pack()
self.update_clock()
self.root.mainloop()
def update_clock(self):
now = time.strftime("%H:%M:%S")
self.label.configure(text=now)
# Put Arrivals in box===============================================================
arrivallb.delete(0, END)
now = dt.datetime.now()
dte = now.strftime("%m-%d-%Y")
conn = sqlite3.connect('reservation.db')
c = conn.cursor()
c.execute("SELECT * FROM reserve")
records = c.fetchall()
for record in records:
if record[22] != "*":
if record[8] == dte:
arrivallb.insert(0, str(record[13]) + " " + record[0] + ", " + record[1])
self.root.after(10000, self.update_clock)
app=App()
Python has a library called ascynio, which is part of the standard library. You can have two or more separate processes (coroutines) running with a long sleep in one of them. Here's a mock program that may or may not work but has the general idea in mind.
Warning: this code hasn't been tested
import asyncio
async def wait(): # you can try and use a while true here
await asyncio.sleep(60)
updateListBox()
return
async def otherStuff():
# code here: make sure it terminates at some point, unless you try the while true method from above
return
async def main():
while True:
await asyncio.gather(
otherStuff(),
wait()
)
asyncio.run(main())
Here's the asyncio documentation https://docs.python.org/3/library/asyncio-task.html
I'm trying to separate my logic (function or task) from main loop. This function usually takes long time to run. In following example calculate() function takes a lot of time to calculate self.time variable.
In other words I want calculate() to be called asynchronously. In every iteration first I would check if calculate() is running, if not then call it. Secondly I would call show() function in every iteration, no matter if calculate() changed self.time value.
import time
import datetime
class Clock:
def __init__(self):
self.time = None
def calculate(self):
time.sleep(3)
self.time = datetime.datetime.now()
def show(self):
print(f"{self.time.minute}:{self.time.second}")
def loop(self):
while True:
self.calculate() # this should be asynchronous
self.show() # this should be called every iteration
if __name__ == '__main__':
clock = Clock()
clock.loop()
Output:
36:9
36:12
36:15
36:18
This is not a wanted outcome. What I want:
36:9
...
36:9
36:9
36:12
...
36:12
36:15
36:15
36:15
...
36:15
36:18
36:18
...
36:18
How I've tried to solve this (this probably not the best solution, so future reader please check answers):
import time
import datetime
import threading
class Clock:
def __init__(self):
self.time = datetime.datetime.now()
self.__thread = None
def calculate(self):
time.sleep(3)
self.time = datetime.datetime.now() # race condition?
def show(self):
print(f"{self.time.minute}:{self.time.second}")
def loop(self):
while True:
if self.__thread is None or not self.__thread.is_alive():
self.__thread = threading.Thread(target=self.calculate)
self.__thread.start()
self.show()
if __name__ == '__main__':
clock = Clock()
clock.loop()
Program output is what I wanted. Is there any flaw in this solution? I can think only of race condition.
I am aware that's not the greatest description of this problem. If you
could help me with editing this post with more searchable and specific
vocabulary I would be grateful. If you have idea for better title please
leave it in comments.
I checked your code in my IDE, and it looks like exactly what you wanted using an acceptable approach. The only alternative solution I can think of is: 1) use a temp variable that goes up by one until it gets to 3 then reset. 2) similar idea but use time.nextTime = 3 to jump every 3 seconds and print current time.
Also, your first code solution seems to take some time to run is because it's waiting 3 seconds to show the time. And regarding race condition, that's not an issue since you're not using multiple threads at the same time in your second solution.
I have been writing a program which runs a remote script on server. So, I need to show the progress with a bar but somehow when I run my code, GUI start to freeze. I have used QThread and SIGNAL but unfortunately couldnt be succedeed.
Here is my code below;
class dumpThread(QThread):
def __init__(self):
QThread.__init__(self)
def __del__(self):
self.wait()
def sendEstablismentCommands(self, connection):
# Commands are sending sequently with proper delay-timers #
connection.sendShell("telnet localhost 21000")
time.sleep(0.5)
connection.sendShell("admin")
time.sleep(0.5)
connection.sendShell("admin")
time.sleep(0.5)
connection.sendShell("cd imdb")
time.sleep(0.5)
connection.sendShell("dump subscriber")
command = input('$ ')
def run(self):
# your logic here
# self.emit(QtCore.SIGNAL('THREAD_VALUE'), maxVal)
self.sendEstablismentCommands(connection)
class progressThread(QThread):
def __init__(self):
QThread.__init__(self)
def __del__(self):
self.wait()
def run(self):
# your logic here
while 1:
maxVal = 100
self.emit(SIGNAL('PROGRESS'), maxVal)
class Main(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.connectButton.clicked.connect(self.connectToSESM)
def connectToSESM(self):
## Function called when pressing connect button, input are being taken from edit boxes. ##
## dumpThread() method has been designed for working thread seperate from GUI. ##
# Connection data are taken from "Edit Boxes"
# username has been set as hardcoded
### Values Should Be Defined As Global ###
username = "ntappadm"
password = self.ui.passwordEdit.text()
ipAddress = self.ui.ipEdit.text()
# Connection has been established through paramiko shell library
global connection
connection = pr.ssh(ipAddress, username, password)
connection.openShell()
pyqtRemoveInputHook() # For remove unnecessary items from console
global get_thread
get_thread = dumpThread() # Run thread - Dump Subscriber
self.progress_thread = progressThread()
self.progress_thread.start()
self.connect(self.progress_thread, SIGNAL('PROGRESS'), self.updateProgressBar)
get_thread.start()
def updateProgressBar(self, maxVal):
for i in range(maxVal):
self.ui.progressBar.setValue(self.ui.progressBar.value() + 1)
time.sleep(1)
maxVal = maxVal - 1
if maxVal == 0:
self.ui.progressBar.setValue(100)
def parseSubscriberList(self):
parsing = reParser()
def done(self):
QtGui.QMessageBox.information(self, "Done!", "Done fetching posts!")
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
I am expecting to see updateProgressBar method has called with SIGNAL, so process goes through seperate thread. I coudlnt find where I am missing.
Thanks for any help
There are really two problems. One thing I have noticed is that Python threads are greedy if they are not used for IO operations like reading from a serial port. If you tell a thread to run a calculation or something that is not IO related a thread will take up all of the processing and doesn't like to let the main thread / event loop run. The second problem is that signals are slow ... very slow. I've noticed that if you emit a signal from a thread and do it very fast it can drastically slow down a program.
So at the heart of the issue, the thread is taking up all of the time and you are emitting a signal very very fast which will cause slow downs.
For clarity and ease of use I would use the new style signal and slots.
http://pyqt.sourceforge.net/Docs/PyQt4/new_style_signals_slots.html
class progressThread(QThread):
progress_update = QtCore.Signal(int) # or pyqtSignal(int)
def __init__(self):
QThread.__init__(self)
def __del__(self):
self.wait()
def run(self):
# your logic here
while 1:
maxVal = 100
self.progress_update.emit(maxVal) # self.emit(SIGNAL('PROGRESS'), maxVal)
# Tell the thread to sleep for 1 second and let other things run
time.sleep(1)
To connect to the new style signal
...
self.progress_thread.start()
self.process_thread.progress_update.connect(self.updateProgressBar) # self.connect(self.progress_thread, SIGNAL('PROGRESS'), self.updateProgressBar)
...
EDIT
Sorry there is another problem. When a signal calls a function you cannot stay in that function forever. That function is not running in a separate thread it is running on the main event loop and the main event loop waits to run until you exit that function.
Update progress sleeps for 1 second and keeps looping. The hanging is coming from staying in this function.
def updateProgressBar(self, maxVal):
for i in range(maxVal):
self.ui.progressBar.setValue(self.ui.progressBar.value() + 1)
time.sleep(1)
maxVal = maxVal - 1
if maxVal == 0:
self.ui.progressBar.setValue(100)
It would be better to write the progress bar like
class progressThread(QThread):
progress_update = QtCore.Signal(int) # or pyqtSignal(int)
def __init__(self):
QThread.__init__(self)
def __del__(self):
self.wait()
def run(self):
# your logic here
while 1:
maxVal = 1 # NOTE THIS CHANGED to 1 since updateProgressBar was updating the value by 1 every time
self.progress_update.emit(maxVal) # self.emit(SIGNAL('PROGRESS'), maxVal)
# Tell the thread to sleep for 1 second and let other things run
time.sleep(1)
def updateProgressBar(self, maxVal):
self.ui.progressBar.setValue(self.ui.progressBar.value() + maxVal)
if maxVal == 0:
self.ui.progressBar.setValue(100)