Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Python multithreaded


May 10, 2021 Python2


Table of contents


Python multithreaded

Multithreaded is similar to executing multiple different programs at the same time, and multithreaded running has the following advantages:

  • Threads allow you to put tasks that occupy a long program in the background.
  • The user interface can be more attractive, such as when a user clicks a button to trigger the processing of certain events, and a progress bar pops up to show the progress of processing
  • The program may run faster
  • Threads are useful for some waiting tasks, such as user input, file read and write, and network sending and receiving data. In this case we can free up some valuable resources such as memory footprint and so on.

Threads are still different from processes in execution. E ach independent thread has an entry point for the program to run, a sequence to execute sequentially, and an exit for the program. H owever, threads can not execute independently and must be controlled by multiple threads that exist in the application.

Each thread has its own set of CPU registers, called the thread's context, which reflects the state of the CPU register in which the thread last ran.

Instruction pointers and stack pointer registers are two of the most important registers in the thread context, and threads always run in the context of the process getting, both of which are used to flag memory in the process address space that owns the thread.

  • Threads can be preempted (interrupted).
  • While other threads are running, threads can be temporarily shelved (also known as sleep) -- this is the thread's retreat.

Start learning Python threads

There are two ways to use threads in Python: functions or classes to wrap thread objects.

Function: Calls the new (start_new_thread function in the thread module to produce a new thread. The syntax is as follows:

thread.start_new_thread ( function, args[, kwargs] )

Description of the parameters:

  • function - thread function.
  • args - an argument passed to a thread function that must be a tuple type.
  • kwargs - optional parameters.

Instance:

#!/usr/bin/python
# -*- coding: UTF-8 -*-


import thread
import time


# 为线程定义一个函数
def print_time( threadName, delay):
   count = 0
   while count < 5:
      time.sleep(delay)
      count += 1
      print "%s: %s" % ( threadName, time.ctime(time.time()) )


# 创建两个线程
try:
   thread.start_new_thread( print_time, ("Thread-1", 2, ) )
   thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
   print "Error: unable to start thread"


while 1:
   pass

The output of the above program is as follows:

Thread-1: Thu Jan 22 15:42:17 2009
Thread-1: Thu Jan 22 15:42:19 2009
Thread-2: Thu Jan 22 15:42:19 2009
Thread-1: Thu Jan 22 15:42:21 2009
Thread-2: Thu Jan 22 15:42:23 2009
Thread-1: Thu Jan 22 15:42:23 2009
Thread-1: Thu Jan 22 15:42:25 2009
Thread-2: Thu Jan 22 15:42:27 2009
Thread-2: Thu Jan 22 15:42:31 2009
Thread-2: Thu Jan 22 15:42:35 2009

The end of a thread generally depends on the natural end of the thread function, or thread.exit() can be called in a thread function, and he throws SystemExit exception to exit the thread.


The thread module

Python provides thread support through two standard libraries, threading and threading. thread provides a low-level, original thread and a simple lock.

Other methods provided by the thread module:

  • threading.currentThread(): Returns the current thread variable.
  • threading.enumerate(): Returns a list that contains a running thread. R unning refers to threads that start, end, and do not include threads before and after startup.
  • threading.activeCount(): Returns the number of threads running with the same result as len (threading.enumerate().)

In addition to using methods, thread modules also provide thread classes to handle threads, and thread classes provide the following methods:

  • run(): A method used to represent thread activity.
  • start(): Start thread activity.

  • join: Wait until the thread aborts. This blocks the calling thread until the thread's join() method is called to abort - exit normally or throw an unprocessed exception - or an optional timeout occurs.
  • IsAlive(): Returns whether the thread is active.
  • getName(): Returns the thread name.
  • setName(): Set the thread name.

Create a thread using the Threading module

Create threads using the Threading module, directly from threading. Thread inherits and then overrides __init__ method and run() method:

#coding=utf-8
#!/usr/bin/python

import threading
import time

exitFlag = 0

class myThread (threading.Thread):   #继承父类threading.Thread
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
    def run(self):                   #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数 
        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:
            thread.exit()
        time.sleep(delay)
        print "%s: %s" % (threadName, time.ctime(time.time()))
        counter -= 1

# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# 开启线程
thread1.start()
thread2.start()

print "Exiting Main Thread"

The results of the implementation of the above procedures are as follows;

Starting Thread-1
Starting Thread-2
Exiting Main Thread
Thread-1: Thu Mar 21 09:10:03 2013
Thread-1: Thu Mar 21 09:10:04 2013
Thread-2: Thu Mar 21 09:10:04 2013
Thread-1: Thu Mar 21 09:10:05 2013
Thread-1: Thu Mar 21 09:10:06 2013
Thread-2: Thu Mar 21 09:10:06 2013
Thread-1: Thu Mar 21 09:10:07 2013
Exiting Thread-1
Thread-2: Thu Mar 21 09:10:08 2013
Thread-2: Thu Mar 21 09:10:10 2013
Thread-2: Thu Mar 21 09:10:12 2013
Exiting Thread-2

Thread synchronization

If multiple threads modify a data together, unpredictable results can occur, and multiple threads need to be synchronized in order to ensure data correctness.

Simple thread synchronization can be achieved with Lock and Rlock of thread objects, both of which have a acquire method and a release method, which can be placed between the acquire and release methods for data that requires only one thread at a time. A s follows:

The advantage of multithreading is that you can run multiple tasks at the same time (at least as it feels). However, when threads need to share data, there may be problems with out-of-step data.

Consider a situation where all elements in a list are 0, the thread "set" changes all elements from back to forward to 1, and the thread "print" is responsible for reading the list and printing it from the back of the trip.

So, maybe when the thread "set" starts to change, the thread "print" will print the list, and the output will be half 0 half 1, which is the different step of the data. T o avoid this, the concept of locks has been introduced.

Locks come in two states - locked and unlocked. W henever a thread, such as "set," wants to access shared data, it must first get locked, if another thread, such as "print," gets locked, then let the thread "set" pause, that is, block synchronously, and wait until the thread "print" access is complete, release the lock, and then let the thread "set" continue.

With this processing, the list is printed with either a full output of 0 or a full output of 1, and there will be no more embarrassment of half 0 and half 1.

Instance:

#coding=utf-8
#!/usr/bin/python

import threading
import time

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):
        print "Starting " + self.name
       # 获得锁,成功获得锁定后返回True
       # 可选的timeout参数不填时将一直阻塞直到获得锁定
       # 否则超时后将返回False
        threadLock.acquire()
        print_time(self.name, self.counter, 3)
        # 释放锁
        threadLock.release()

def print_time(threadName, delay, counter):
    while counter:
        time.sleep(delay)
        print "%s: %s" % (threadName, time.ctime(time.time()))
        counter -= 1

threadLock = threading.Lock()
threads = []

# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# 开启新线程
thread1.start()
thread2.start()

# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)

# 等待所有线程完成
for t in threads:
    t.join()
print "Exiting Main Thread"

Thread Priority Queue (Queue)

Python's Queue module provides synchronized, thread-safe queue classes, including FIFO (first in, first out) queue Queue, LIFO (first in, first out) queue LifoQueue, and priority queue PriorityQueue. T hese queues implement lock synths and can be used directly in multiple threads. You can use queues to synchronize threads.

Common methods in the Queue module:

  • Queue.qsize() returns the size of the queue
  • Queue.empty() If the queue is empty, return True, and false
  • Queue.full() If the queue is full, return True, and false
  • Queue.full corresponds to the maxsize size
  • Queue.get ('block', timeout') gets the queue, timeout wait time
  • Queue.get_nowait () quite Queue.get (False)
  • Queue.put (item) writes to the queue, timeout wait time
  • Queue.put_nowait (item) quite Queue.put (item, False)
  • Queue.task_done () after completing a job, the Queue.task_done() function sends a signal to the queue that the task has completed
  • Queue.join() actually means waiting until the queue is empty before doing something else

Instance:

#coding=utf-8
#!/usr/bin/python

import Queue
import threading
import time

exitFlag = 0

class myThread (threading.Thread):
    def __init__(self, threadID, name, q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.q = q
    def run(self):
        print "Starting " + self.name
        process_data(self.name, self.q)
        print "Exiting " + self.name

def process_data(threadName, q):
    while not exitFlag:
        queueLock.acquire()
        if not workQueue.empty():
            data = q.get()
            queueLock.release()
            print "%s processing %s" % (threadName, data)
        else:
            queueLock.release()
        time.sleep(1)

threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = Queue.Queue(10)
threads = []
threadID = 1

# 创建新线程
for tName in threadList:
    thread = myThread(threadID, tName, workQueue)
    thread.start()
    threads.append(thread)
    threadID += 1

# 填充队列
queueLock.acquire()
for word in nameList:
    workQueue.put(word)
queueLock.release()

# 等待队列清空
while not workQueue.empty():
    pass

# 通知线程是时候退出
exitFlag = 1

# 等待所有线程完成
for t in threads:
    t.join()
print "Exiting Main Thread"

The results of the above procedure execution:

Starting Thread-1
Starting Thread-2
Starting Thread-3
Thread-1 processing One
Thread-2 processing Two
Thread-3 processing Three
Thread-1 processing Four
Thread-2 processing Five
Exiting Thread-3
Exiting Thread-1
Exiting Thread-2
Exiting Main Thread