课程: Programming Concepts for Python
Polling
- There will be times when you need a program to detect that some event has occurred and then react to that event by performing a certain action. To accomplish that, there are two approaches you could use, polling or event-driven programming. With the polling method, a program is continuously checking and checking and checking and actively checking for a certain condition to occur, like a button being pressed, and when it sees that the condition has occurred, it'll then perform an appropriate action. My house is ready for my friends, so now I'm just waiting for the pizza delivery guy to get here. When the pizza man arrives, I'll need to perform the appropriate action by opening the door and getting the pizza. So how will I know when the pizza man is on the front porch to get my pizza? Well, I could try the polling method, and to do that, I'll have to get up off my bed. Then I go down the stairs. (door clicks) I check to see if he's here, not yet. (door clicks) So then I head back up the stairs and then I return back to lounging, but as soon as I lay back down, I got to get right back up again and check and see if he's here. I go down the stairs again. (door clicks) Nope, still not here. (door clicks) Back up the stairs I go, lay down, stand up, down the stairs another time, not yet. (door clicks) Up again, down, up, down again. (door clicks) Nope, and back up the stairs again. Whew, that's exhausting! As you can see, polling is not a very efficient method. It takes a lot of energy for me to run up and down these stairs, checking for a status that rarely occurs. It also prevents me from doing something else with my Saturday afternoon. A computer application that implements a polling routine uses a lot of cycles, checking for that rarely occurring status, And simple, low-level programs like you might write for a microcontroller with a language like C, using polling to do software-driven I/O might be perfectly acceptable. If the program is the only thing running on the microcontroller, it doesn't matter if we spend a lot of cycles polling. Higher-level applications and languages like Python or Java are usually responding to events from things like a graphical user interface. For that, using a polling routine would be pretty wasteful, but there may be times when polling is your only option. So let's look at some example code that implements polling in Python. This example script represents the scenario we just saw when I ran up and down the stairs to see if the pizza delivery person had arrived. Near the top of the script, we create a variable named hungry at line 3, which indicates my current status and it's initialized to True because I'm hungry. That's why I need pizza. After that, the program enters into a while loop at line 5, which will continuously execute as long as hungry is still true. Inside the loop, I open the front door, which we simulate by opening a text file called front_door.txt. The open function returns a file object, which is bound to the variable name front door at line 7. Let's take a quick look at that text file, which is included in the same directory of the exercise files. This file contains the things that are outside my front door. I currently have a welcome mat and a doorbell, but sadly, no pizza delivery person. Looking back at the script after opening the text file, the if statement at line 9 checks whether or not the string delivery person exists in that front_door text file. If it does, then I give a shout of joy announcing that the pizza's here and set hunger to False. However, if the delivery person is not at the front door, then I'll say in a very hungry voice, "Not yet..." After that, I'll complete the loop by closing the front door, which is simulated by closing the file object at line 16. If the pizza had arrived and I'm no longer hungry, then the while loop will exit after closing the door. Otherwise, as we saw earlier, the while loop will execute again and again and again and again and again as I keep on checking. Now to execute this script from within the directory it lives in so that it can find the front_door text file, I'll right click on its parent directory within VS Code, I'll select the open and integrated terminal option, and then I'll call Python to run the script. We can see that the while loop is running over and over as fast as it can to check for the pizza to arrive. Since that routine is running nonstop, we are basically spending an entire processor core just to check if the pizza person is downstairs, which is not very efficient. We can make that pizza person arrive by modifying the front_door text file to have delivery person in it. As soon as that change is saved to file, the polling routine will see that they've arrived. I'll announce that the pizza's here and the while loop will finish up and exit. This example demonstrates why you should not use a free running while loop to implement a polling routine. When you create a polling routine, it's usually a good idea to include some sort of delay mechanism in the loop to keep it from running nonstop, which can waste CPU resources and prevent other things from running, or at least slow them down. In Python, we can do that by importing the time module at the top of our script. Then we'll add the time.sleep function at the very end of this while loop. This will cause the program to wait for one second when it gets to that line. After I close the front door, I'll rest for one second before going to check again. Now, before running that script, let's remove the pizza delivery person from the front_door text file, then call Python to execute that script again from within the terminal. It's not totally obvious just looking at the output, but now the while loop doesn't run nonstop at full speed. It's only checking for the pizza person to arrive once every second, and by doing that, we are not overwhelming the CPU. The reason that works is because the sleep function uses a mechanism called an interrupt, which allows the program to sleep in a way that doesn't waste normal CPU cycles, and then it wakes up after a second to continue on executing.