什么叫Python3 多线程?如何学多线程?教你一招

Python3 线程中常用的两个模块为:

_thread

threading(推荐使用)

thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 Python3 中不能再使用"thread" 模块。为了兼容性,Python3 将 thread 重命名为 "_thread"。

开始学习 Python 线程

Python 中使用线程有两种方式:函数或者用类来包装线程对象。

函数式:调用 _thread 模块中的 start_new_thread() 函数来产生新线程。语法如下:

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

参数说明:

function - 线程函数。

args - 传递给线程函数的参数,他必须是个 tuple 类型。

kwargs - 可选参数。

实例:

#!/usr/bin/python3

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: 无法启动线程")

while 1:

  pass

执行以上程序输出结果如下:

Thread-1: Wed Apr  6 11:36:31 2016

Thread-1: Wed Apr  6 11:36:33 2016

Thread-2: Wed Apr  6 11:36:33 2016

Thread-1: Wed Apr  6 11:36:35 2016

Thread-1: Wed Apr  6 11:36:37 2016

Thread-2: Wed Apr  6 11:36:37 2016

Thread-1: Wed Apr  6 11:36:39 2016

Thread-2: Wed Apr  6 11:36:41 2016

Thread-2: Wed Apr  6 11:36:45 2016

Thread-2: Wed Apr  6 11:36:49 2016

执行以上程后可以按下 ctrl-c to 退出。

线程模块

Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。

_thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。

threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:

threading.currentThread(): 返回当前的线程变量。

threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。

threading.activeCount(): 返回正在运行的线程数量,与 len(threading.enumerate()) 有相同的结果。

使用 threading 模块创建线程

我们可以通过直接从 threading.Thread 继承创建一个新的子类,并实例化后调用 start() 方法启动新线程,即它调用了线程的 run() 方法:

#!/usr/bin/python3

import threading

import time

exitFlag = 0

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 ("开始线程:" + self.name)

        print_time(self.name, self.counter, 5)

        print ("退出线程:" + self.name)

def print_time(threadName, delay, counter):

    while counter:

        if exitFlag:

            threadName.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()

thread1.join()

thread2.join()

print ("退出主线程")

以上程序执行结果如下;

开始线程:Thread-1

开始线程:Thread-2

Thread-1: Wed Apr  6 11:46:46 2016

Thread-1: Wed Apr  6 11:46:47 2016

Thread-2: Wed Apr  6 11:46:47 2016

Thread-1: Wed Apr  6 11:46:48 2016

Thread-1: Wed Apr  6 11:46:49 2016

Thread-2: Wed Apr  6 11:46:49 2016

Thread-1: Wed Apr  6 11:46:50 2016

退出线程:Thread-1

Thread-2: Wed Apr  6 11:46:51 2016

Thread-2: Wed Apr  6 11:46:53 2016

Thread-2: Wed Apr  6 11:46:55 2016

退出线程:Thread-2

退出主线程

线程同步

使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。如下:

多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)。但是当线程需要共享数据时,可能存在数据不同步的问题。

考虑这样一种情况:一个列表里所有元素都是 0,线程"set"从后向前把所有元素改成 1,而线程"print"负责从前往后读取列表并打印。

那么,可能线程"set"开始改的时候,线程"print"便来打印列表了,输出就成了一半 0 一半 1,这就是数据的不同步。为了避免这种情况,引入了锁的概念。

锁有两种状态——锁定和未锁定。每当一个线程比如"set"要访问共享数据时,必须先获得锁定;如果已经有别的线程比如"print"获得锁定了,那么就让线程"set"暂停,也就是同步阻塞;等到线程"print"访问完毕,释放锁以后,再让线程"set"继续。

经过这样的处理,打印列表时要么全部输出 0,要么全部输出 1,不会再出现一半 0 一半 1 的尴尬场面。

实例:

#!/usr/bin/python3

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 ("开启线程: " + self.name)

        # 获取锁,用于线程同步

        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 ("退出主线程")

执行以上程序,输出结果为:

开启线程: Thread-1

开启线程: Thread-2

Thread-1: Wed Apr  6 11:52:57 2016

Thread-1: Wed Apr  6 11:52:58 2016

Thread-1: Wed Apr  6 11:52:59 2016

Thread-2: Wed Apr  6 11:53:01 2016

Thread-2: Wed Apr  6 11:53:03 2016

Thread-2: Wed Apr  6 11:53:05 2016

退出主线程

线程优先级队列( Queue)

Python 的 Queue 模块中提供了同步的、线程安全的队列类,包括 FIFO(先入先出)队列 Queue,LIFO(后入先出)队列 LifoQueue,和优先级队列 PriorityQueue。

这些队列都实现了锁原语,能够在多线程中直接使用,可以使用队列来实现线程间的同步。

Queue 模块中的常用方法:

Queue.qsize() 返回队列的大小

Queue.empty() 如果队列为空,返回 True,反之 False

Queue.full() 如果队列满了,返回 True,反之 False

Queue.full 与 maxsize 大小对应

Queue.get([block[, timeout]]) 获取队列,timeout 等待时间

Queue.get_nowait() 相当 Queue.get(False)

Queue.put(item) 写入队列,timeout 等待时间

实例:

#!/usr/bin/python3

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 ("开启线程:" + self.name)

        process_data(self.name, self.q)

        print ("退出线程:" + 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 ("退出主线程")

以上程序执行结果:

开启线程:Thread-1

开启线程:Thread-2

开启线程:Thread-3

Thread-3 processing One

Thread-1 processing Two

Thread-2 processing Three

Thread-3 processing Four

Thread-1 processing Five

退出线程:Thread-3

退出线程:Thread-2

退出线程:Thread-1

退出主线程

————————————————

版权声明:本文为CSDN博主「沅沅说python」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qxr333000/article/details/120178026

你可能感兴趣的:(什么叫Python3 多线程?如何学多线程?教你一招)