Python3教程:多线程的使用教程

一、简介

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

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

参数说明:

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

实例:

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

二、线程模块

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

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

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

  • threading.currentThread(): 返回当前的线程变量。
  • threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  • threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:

  • run(): 用以表示线程活动的方法。
  • start():启动线程活动。
  • join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
  • isAlive(): 返回线程是否活动的。
  • getName(): 返回线程名。
  • setName(): 设置线程名。

三、使用 threading 模块创建线程

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

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

五、线程优先级队列( Queue)

1、queue队列

1.python3中的队列模块是queue,不是Queue

2.一般涉及到同步,多线程之类用到队列模块

3.定义了 queue.Queue 类,以及继承它的 queue.LifoQueue 类 和 queue.PriorityQueue 类 和 queue.SimpleQueue 类

4.分别对应队列类(FIFO先进先出),LIFO后进先出队列类,优先队列,无边界FIFO简单队列类

5.还有两个异常:队满和队空

2、队列queue公共方法

'''
学习中遇到问题没人解答?小编创建了一个Python学习交流群:857662006
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
import queue

#创建基本队列
#queue.Queue(maxsize=0)创建一个队列对象(队列容量),若maxsize小于或者等于0,队列大小没有限制
Q=queue.Queue(10)
print(Q)
print(type(Q))

#1.基本方法
print(Q.queue)#查看队列中所有元素
print(Q.qsize())#返回队列的大小
print(Q.empty())#判断队空
print(Q.full())#判断队满

#2.获取队列,0--5
#Queue.put(item,block = True,timeout = None )将对象放入队列,阻塞调用(block=False抛异常),无等待时间
for i in range(5):
    Q.put(i)
# Queue.put_nowait(item)相当于 put(item, False).


#3.读队列,0--5
#Queue.get(block=True, timeout=None)读出队列的一个元素,阻塞调用,无等待时间
while not Q.empty():
    print(Q.get())
# Queue.get_nowait()相当于get(False).取数据,如果没数据抛queue.Empty异常


#4.另两种涉及等待排队任务的方法
# Queue.task_done()在完成一项工作后,向任务已经完成的队列发送一个信号
# Queue.join()阻止直到队列中的所有项目都被获取并处理。即等到队列为空再执行别的操作

3、其他

1.LifoQueue: LIFO后进先出

2.PriorityQueue:优先级队列,如果数据元素不具有可比性,则可将数据包装在忽略数据项的类中,仅比较优先级编号

3.SimpleQueue:简单队列,无跟踪任务的功能

六、Queue详细参数和用法实例

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等待时间
  • Queue.put_nowait(item) 相当Queue.put(item, False)
  • Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
  • Queue.join() 实际上意味着等到队列为空,再执行别的操作

实例:

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

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python3教程:多线程的使用教程 - Python技术站

(0)
上一篇 2023年4月2日
下一篇 2023年4月2日

相关文章

  • Python函数与码复用

    一.函数的定义与使用 1.函数的定义与使用方法 函数是一段代码的表示,它对应了一段具有特定功能的、可重用的语句组,它是一种功能的抽象,它表达特定的含义。在一般编程中,函数有两个作用,它通过函数定义一段功能,可以降低编码难度,同时也可以对一段代码进行复用。 函数的使用方法如下,其中函数体指的是函数内部包含的一些语句代码: def <函数名>(&lt…

    python 2023年4月22日
    00
  • Python中的交互库-os库

    一.介绍 os库是与操作系统相关的库,它提供了通用的基本的操作系统交互功能。os库是Python的标准库之一,它里面包含几百个处理函数,能够处理与操作系统相关的功能,包括路径操作、进程管理、环境参数设置等几类功能。其中路径操作是利用os.path子库,它用于处理文件以及目录的路径,并获得相关的信息;进程管理指启动系统中的其它程序的功能;环境参数指获得系统软硬…

    python 2023年5月10日
    00
  • Python推导式创建数列的方法

    一、列表推导式 列表推导式生成列表对象,语法如下: ”’ [表达式 for item in 可迭代对象] 或者 [表达式 for item in 可迭代对象 if 条件判断] ”’ 例子 l1 = [x for x in range(5)] print(l1) # [0, 1, 2, 3, 4] l2 = [x*2 for x in range(1,5)…

    Python开发 2023年4月2日
    00
  • Python3教程:加密模块-hashlib

    一、哈希 1. 什么是可哈希(hashable) 简要的说,可哈希的数据类型,即不可变的数据结构(字符串str、元组tuple、对象集objects)。 2. 哈希有什么作用 它是一个将大体量数据转化为很小数据的过程,甚至可以仅仅是一个数字,以便我们可以用在固定的时间复杂度下查询它,所以,哈希对高效的算法和数据结构很重要。 3. 什么是不可哈希(unhash…

    Python开发 2023年4月2日
    00
  • python学习:三目运算符

    一、三目运算符的基本语法 不同语言的三目运算符的基本语法存在差异,以C语言和Python语言为例。 1、通常一般语言如C语言的语言格式如下: 判断条件(返回布尔值) ? 为真时的结果 :为假时的结果 实例: #include<stdio.h> int main(void) { int x=2; x = x%2==0 ? x+1 : x; prin…

    Python开发 2023年4月2日
    00
  • Python中的异常处理总结

    1.异常分类 错误Error: 原因 示例 笔误 像变量名写错,造成的语法错误 逻辑错误 算法写错了,例如原本逻辑是求和,但写成了乘积 函数或者类使用错误 这类也归为逻辑错误 写代码时,错误是可以避免的。 异常Exception 有时候程序写的没有问题,也没有语法错误,但在某些情况下依然出现一些意外,导致程序无法正常执行,就是通常所说的异常。 例如open函…

    Python开发 2023年3月31日
    00
  • Python学习:绑定方法与非绑定方法

    一、绑定方法与非绑定方法 类中定义的函数分为两大类:绑定方法和非绑定方法 其中绑定方法又分为绑定到对象的对象方法和绑定到类的类方法。 在类中正常定义的函数默认是绑定到对象的,而为某个函数加上装饰器@classmethod后,该函数就绑定到了类。 我们在之前的章节中已经介绍过对象方法了,本节我们主要介绍类方法。类方法通常用来在__init__的基础上提供额外的…

    Python开发 2023年4月2日
    00
  • python学习:枚举定义和使用

    1.定义 在某些情况下,一个类的对象是有限且固定的,比如季节类,它只有 4 个对象;再比如行星类,目前只有 8 个对象。这种实例有限且固定的类,在 Python 中被称为枚举类。程序有两种方式来定义枚举类: 直接使用 Enum 列出多个枚举值来创建枚举类。 通过继承 Enum 基类来派生枚举类。 2.使用 使用 Enum 列出多个枚举值来创建枚举类 如下程序…

    Python开发 2023年4月2日
    00
合作推广
合作推广
分享本页
返回顶部