Program "I can't stop ..." I "Please stop"
This article is the 7th day article of N High School Advent Calendar 2019. I am currently in my second year of second grade (there were many things when I transferred) and am attending a school course. N High is very grateful that I can do my own project in programming time as long as I finish the essential tasks.
In this article, I'll write about the problems I faced while making Discord and Twitter bots in Python. Please point out any mistakes.
When I tried to stop a program using Python threading with Keyboard Interrupt (Ctrl + C), it didn't stop at once for some reason.
Upon further investigation, sys.exit ()
did not stop.
OS: Windows 10 Home Runtime: Python 3.8.0
For the time being, I decided to write code using threading for verification.
import threading
import time
#Function definition
def a():
for i in range(5):
time.sleep(1)
print("A" + str(i))
def b():
time.sleep(0.5)
for j in range(5):
time.sleep(1)
print("B" + str(j))
#Thread object creation
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)
#Run
t1.start()
t2.start()
#Wait until the end
t1.join()
t2.join()
print("Finish")
As expected, the output looks like this: Finish was displayed at the same time as B4 was displayed.
A0
B0
A1
B1
A2
B2
A3
B3
A4
B4
Finish
Now, let's remodel this into an infinite loop.
import threading
import time
#Function definition
def a():
c=1
while True:
time.sleep(1)
print("A" + str(c))
c+=1
def b():
k=1
time.sleep(0.5)
while True:
time.sleep(1)
print("B" + str(k))
k+=1
#Thread object creation
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)
#Run
t1.start()
t2.start()
#Wait until the end
t1.join()
t2.join()
The output is as follows.
A1
B1
A2
B2
A3
B3
^CTraceback (most recent call last):
File "***********.py", line 28, in <module>
t1.join()
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 1011, in join
self._wait_for_tstate_lock()
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 1027, in _wait_for_tstate_lock
elif lock.acquire(block, timeout):
KeyboardInterrupt
A4
B4
A5
B5
A6
B6
^CException ignored in: <module 'threading' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py'>
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 1388, in _shutdown
lock.acquire()
KeyboardInterrupt:
For some reason it didn't stop at the first Keyboard Interrupt. This time I did it twice and it stopped, but I want to avoid it if possible.
You don't have to "wait until the end". In other words, just delete **. Join ()
.
When I actually delete t1.join ()
and t2.join ()
and execute it, it becomes like this.
A1
B1
A2
B2
^CException ignored in: <module 'threading' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py'>
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 1388, in _shutdown
lock.acquire()
KeyboardInterrupt:
There was a time when I was thinking, "If it's a process that uses While True, it won't end in the middle, and if you stop with Ctrl + C, yeah." But there are surprising scenes that I want to stop. For example, when you want to shut down a bot with a command. The following contents were discovered at that time.
sys.exit ()
doesn't work eitherimport threading
import time
import sys
#Function definition
def a():
c=1
while True:
time.sleep(1)
print("A" + str(c))
c+=1
def b():
k=1
time.sleep(0.5)
while True:
time.sleep(1)
print("B" + str(k))
k+=1
#Thread object creation
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)
#Run
t1.start()
t2.start()
#forced termination
print("Terminate")
sys.exit()
print("Terminated")
The expected output is a Terminate
line. This is because the program should not be executed after sys.exit ()
(this is strictly wrong, as described later).
However, when this is actually operated, the following output is obtained.
Terminate
A1
B1
A2
B2
A3
B3
A4
B4
sys.exit ()
runs after Terminate
, and Terminated
is hidden, but the above two functions have been executed normally.
There was a mistake in recognizing sys.exit ()
. It doesn't stop the whole program, it stops the thread.
The only thread that stops in the above program is the thread that is executing print ("Terminate ")
, and sys.exit ()
has not arrived at the two threads that are in an infinite loop.
One way to stop it is to run sys.exit ()
inside the thread object.
But what I want to do is "stop all threads at once".
Daemon threads other than the main thread.
import threading
import time
import sys
#Function definition
def a():
c=1
while True:
time.sleep(1)
print("A" + str(c))
c+=1
def b():
k=1
time.sleep(0.5)
while True:
time.sleep(1)
print("B" + str(k))
k+=1
def c():
while True:
n = input()
if n == "e":
print("Terminate")
sys.exit()
#Thread object creation
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)
#Daemonization
t1.setDaemon(True)
t2.setDaemon(True)
#Run
t1.start()
t2.start()
c() # c()Only run on the main thread
Changed to run sys.exit ()
when receiving input ʻe`.
The output result is as follows.
A1
B1
A2
e
Terminate
If you press e and press Enter (Return), execution will stop there.
The daemon thread behaves as ** automatically disappearing when a thread other than the daemon thread is not running **.
If there is only one process that includes sys.exit ()
, it may be better to run it on the main thread, that is, on the outermost side without doing threading.Thread ()
.
To be honest, I tried to find out the cause, but I don't know. Somehow the signal was something like that, but I can't write it correctly with my own skill, so I won't post it. I researched a lot about threading in the process of writing this article, but it seems that there are still various functions, and there may be ways to realize what I want to do other than those listed above. However, if I try to do it within the scope of my understanding, it will be as above. If this gets stuck, I'll try to find another way.
Recommended Posts