This article aims to explain how we can use scheduling threading in Python to make it a priority. Here, we’ll talk about scheduling a priority thread in Python and using it with a good example program.
With Python threading, we can run different parts of our program simultaneously, making your program’s design easier. We will show you how to use threads to speed up your Python program if you know some Python.
Threading in Python
Threading is the capability to execute multiple instructions simultaneously. As we explore in this article, we can prioritize the threads by adjusting the scheduling.
A global interpreter lock (GIL) is used to implement Python threads, meaning a thread’s priority cannot be controlled. Controlling threads using a priority requires us to create an implicit priority system.
In threading, you can imagine two (or more) processors running on your program simultaneously, each performing an independent task.
That’s very close to being true. Each thread will run on one processor simultaneously, even on different processors.
To run multiple tasks simultaneously, you’ll need a non-standard Python implementation, your code may need to be written in a different language, or you may need to use multiprocessing with additional overhead.
Python’s C implementation does not always support threading, so threading may not speed up all tasks. GIL interactions limit the number of Python threads that can run simultaneously.
Generally, threading is a suitable choice for tasks that spend a lot of time waiting for external events. It’s possible that problems requiring heavy CPU computation but spending little time waiting for external events won’t run as fast as others.
Controlling Scheduling Priority of Python Threads
Ensuring we are working with the correct version of Python is crucial. We are using version 3.10.4 specifically for this article.
It is possible to check the currently installed python version by running the following command in the terminal.
Importing Useful Libraries
The next step is learning how to make a thread using scheduling priority after understanding what a thread is. Most of the primitives you’ll see in this article are provided by the Python standard library through threading.
In this module,
Thread provides a nice interface for interacting with threads, encapsulating them nicely.
Now we move on to the next phase of the program, where we import the libraries required for scheduling the priorities of Python threads.
import time from threading import Thread from time import sleep
It is possible to start a separate thread by using the
Thread instance and telling it to
import logging import threading import time def the_thread_function(name): logging.info("The thread %s: Beginning now", name) time.sleep(2) logging.info("The Thread %s: Ends", name) if __name__ == "__main__": format = "%(asctime)s: %(message)s" logging.basicConfig(format=format, level=logging.INFO, datefmt="%H:%M:%S") logging.info("Main : Now before creating a thread") x = threading.Thread(target=the_thread_function, args=(1,)) logging.info("Main : Earlier than running threading") x.start() logging.info("Main : Now wait for the thread to End") # x.join() logging.info("Main : All Finish")
17:06:51: Main : Now before creating a thread 17:06:51: Main : Earlier than running threading 17:06:51: The thread 1: Beginning now 17:06:51: Main : Now wait for the thread to End 17:06:51: Main : All Finish 17:06:53: The Thread 1: Ends
In the logging statements, you can see that the main section is creating and starting the thread: You create a thread by passing it an argument list and the function you wish to call.
In this case, the
Thread is told to run
thread_function() and pass it 1 as an argument.
Working With Many Threads Schedule Priority in Python
Currently, the example code works only with two threads, the main thread and the thread you started with the threading
Thread object. You will often want to start many threads and have them work on interesting things.
Next, let’s look at an easier method for doing that. Let’s start by looking at the more difficult way.
import logging import threading import time def thread_function(name): logging.info("Thread %s: Beginning", name) time.sleep(2) logging.info("Thread %s: Ending", name) if __name__ == "__main__": format = "%(asctime)s: %(message)s" logging.basicConfig(format=format, level=logging.INFO, datefmt="%H:%M:%S") threads = list() for index in range(3): logging.info("Main : create and start thread %d.", index) x = threading.Thread(target=thread_function, args=(index,)) threads.append(x) x.start() for index, thread in enumerate(threads): logging.info("Main : Before joining thread %d.", index) thread.join() logging.info("Main : thread %d end", index)
17:09:01: Main : create and start thread 2. 17:09:01: Thread 2: Beginning 17:09:01: Main : Before joining thread 0. 17:09:03: Thread 0: Ending 17:09:03: Main : thread 0 end 17:09:03: Main : Before joining thread 1. 17:09:03: Thread 1: Ending 17:09:03: Main : thread 1 end 17:09:03: Main : Before joining thread 2. 17:09:03: Thread 2: Ending 17:09:03: Main : thread 2 end
We start a thread the same way we started a thread earlier, by creating a
Thread object and then calling
.start(). Keeping a list of
Thread objects allows the program to wait for them later using
When you look at the output carefully, you’ll notice that all three threads get started in the order you might expect. In this case, however, they finish in the opposite order!
Multiple runs will produce and output the different orders. Look for the
Thread x: Nearing End message to tell you when each
Thread will go to the end.
Operating systems determine the order in which threads are run, which is quite difficult to predict. Using threading in algorithms may (and probably will) vary from run to run, so keep that in mind when developing algorithms.
It is a great thing that Python provides several primitives for coordinating threads and coordinating them with one another. We’ll first look at how to make managing a group of threads easier.
worker class allows us to set the script so that each thread can have its execution time. As in the form of a result, we will make the other threads sleep longer if one thread has a higher priority.
Worker class is a simple MFC class that helps you with multi-threading. Any object that requires its thread to perform work inherits from the
Use the Do-Work function to execute the long process - and then use
Pause on the object to perform it.
import time from threading import Thread from time import sleep class Worker(Thread): def __init__(self,pri): Thread.__init__(self) self.pri=pri def run(self): for i in range(20): sleep(1.0*self.pri) print (" -thread with priority:",self.pri) w1=Worker(1.0) w2=Worker(0.75) w3=Worker(0.5) start = time.time() w1.start() w2.start() w3.start() end = time.time()
As part of this step, we have initialized workers. Following that, we have created multiple threads with different priorities.
The worker threads will now be executed as follows:
Output exceeds the size limit. Open the full output data in a text editor -thread with priority: 0.5 -thread with priority: 0.75 -thread with priority: 1.0 -thread with priority: 0.5 -thread with priority: 0.75 -thread with priority: 0.5 -thread with priority: 1.0 -thread with priority: 0.5 -thread with priority: 0.75 -thread with priority: 0.5 -thread with priority: 1.0 -thread with priority: 0.75
On average, we will see that the threads with 0.5 and 0.75 priorities were called more often than the threads with 1.0 priorities after execution by looking at the output trace of the thread execution.
The following example shows how a simple Python script can schedule a Python thread based on a priority.
We have now seen some examples of Python threading and how to build threaded programs with many threads, scheduling priority, and the problems they solve. The use of
worker classes, and many other methods have also been demonstrated.
We hope you find this article helpful in understanding how to use the threads in Python.