Python多线程原理与用法详解

yipeiwu_com5年前Python基础

本文实例讲述了Python多线程原理与用法。分享给大家供大家参考,具体如下:

多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理(Chip-level multithreading)或同时多线程(Simultaneous multithreading)处理器。[1] 在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理(Multithreading)”。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程(台湾译作“执行绪”),进而提升整体处理性能。

创建并启动一个线程

import threading
def runtask(name):
  print("%s线程已启动"%name)
t = threading.Thread(target=runtask,args=("task1",))  # args因为是一个元组,所以必须这样写,否则运行将报错
t.start()

join

等待当前线程执行完毕

import threading
import time
def runtask(name):
  print("%s线程已启动"%name)
  time.sleep(2)
t = threading.Thread(target=runtask,args=("task1",))
t.start()
t.join()
print("abc")  # 过了2s才会打印,若无等待将看不到等待2s的效果

setDaemon(True)

将线程设置为守护线程。若设置为守护线程,主线程结束后,子线程也将结束,并且主线程不会理会子线程是否结束,主线程不会等待子线程结束完后才结束。若没有设置为守护线程,主线程会等待子线程结束后才会结束。

active_count

程序的线程数量,数量=主线程+子线程数量

Lock(互斥锁)

Python编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为” 互斥锁” 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。在Python中我们使用threading模块提供的Lock类。

import threading,time
def runtask(name):
  global count
  time.sleep(1)
  lock.acquire()   # 获取锁资源,并返回是否获取成功
  count+=1
  print(name,count)
  lock.release()   # 释放资源
count = 0
lock = threading.Lock()   # 互斥锁
for index in range(50):
  t = threading.Thread(target=runtask,args=("thread%d"%index,))
  t.start()

上面这段代码如果没有加上互斥锁,在Python2.x中执行的结果将会是乱的。在Python3.x中执行却总是正确的,似乎是自动为其加了锁

RLock(递归锁,可重入锁)

当一个线程中遇到锁嵌套情况该怎么办,又会遇到什么情况?

def run1():
  global count1
  lock.acquire()
  count1 += 1
  lock.release()
  return count1
def run2():
  global count2
  lock.acquire()
  count2 += 1
  lock.release()
  return count2
def runtask():
  lock.acquire()
  r1 = run1()
  print("="*30)
  r2 = run2()
  lock.release()
  print(r1,r2)
count1,count2 = 0,0
lock = threading.Lock()
for index in range(50):
  t = threading.Thread(target=runtask,)
  t.start()

这是一个很简单的线程锁死案例,程序将被卡死,停止不动。为了解决这一情况,Python提供了递归锁RLock(可重入锁)。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的代码只需做一些小小的改动

lock = threading.Lock()

修改为:

lock = threading.RLock()

那么程序将不会发生死锁情况。

最大可执行线程

threading.BoundedSemaphore(5)设置可同时执行的最大线程数为5个,后面的线程需排队等待前面的线程执行完毕

import time,threading
def runtask(name):
  global num
  semaphore.acquire()
  time.sleep(1)
  num += 1
  semaphore.release()
  print(name,num)
num = 0
semaphore = threading.BoundedSemaphore(5)
for index in range(50):
  t = threading.Thread(target=runtask,args=("线程%s"%index,))
  t.start()

执行效果:

可以看出上面的程序是每次只有5个线程在同时运行,其他线程需等待前面的线程执行完毕,这就是最大可执行线程。

Event

Python提供了Event对象用于线程间通信,它是由线程设置的信号标志,如果信号标志位为假,则线程等待直到信号被其他线程设置成真。Event中提供了四个重要的方法来满足基本的需求。

  • - clear:清除标记
  • - set:设置标记
  • - is_set:是否被标记
  • - wait:等待被标记

代码示例:

import threading,time
def lighter():
  num = 0
  event.set()   # 设置标记
  while True:
    if num >= 5 and num < 10:
      event.clear()  # 清除标记
      print("红灯亮起,车辆禁止通行")
    if num >= 10:
      event.set()   # 设置标记
      print("绿灯亮起,车辆可以通行")
      num = 0
    num += 1
    time.sleep(1)
def car():
  while True:
    if event.is_set():
      print("车辆正在跑...")
    else:
      print("车辆停下了")
      event.wait()
    time.sleep(1)
event = threading.Event()
t1 = threading.Thread(target=lighter,)
t2 = threading.Thread(target=car,)
t1.start()
t2.start()

这是一个简单的红灯停绿灯行案例。初始设置为绿灯并标记,车辆看到标记后通行,当红灯亮起的时候取消标记,车辆看到没有标记时停下,等待标记。

Queue队列

使任务按照某一种特定顺序有条不紊的进行。下面介绍几种常用的队列:

  • - queue.Queue():先进先出
  • - queue.LifoQueue():先进后出
  • - queue.PriorityQueue:优先级队列,优先级的值越小,越先执行

下面介绍几种常用的方法:

  • - get():获取item,如果队列已经取空将会卡住。可设置timeout参数,给定一个超时的值,或者设置参数block=False,队列空直接抛异常
  • - get_nowait():b获取item。如果队列取空了,将会直接抛异常
  • - put():放入队列
  • - empty():队列是否为空
  • - qsize():获取队列的item数量

更多关于Python相关内容感兴趣的读者可查看本站专题:《Python进程与线程操作技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》、《Python+MySQL数据库程序设计入门教程》及《Python常见数据库操作技巧汇总

希望本文所述对大家Python程序设计有所帮助。

相关文章

用Python调用win命令行提高工作效率的实例

用Python调用win命令行提高工作效率的实例

作为程序猿,每天一上班打开电脑要做的时候就是打开各种工作所需的工具,如QQ,SQL Server,浏览器,编辑器等,每天都要一个个点,重复性的工作做多了也觉得烦(关键是影响了我上班倒水的...

使用python绘制人人网好友关系图示例

代码依赖:networkx matplotlib 复制代码 代码如下: #! /bin/env python# -*- coding: utf-8 -*-import urll...

使用Python制作缩放自如的圣诞老人(圣诞树)

使用Python制作缩放自如的圣诞老人(圣诞树)

圣诞节又要到了,虽说我们中国人不提倡过西方的节日,但是商家们还是很喜欢的,估计有对象的男孩纸女孩纸们也很喜欢吧。 今天的主题是为大家展示如何用python做一个不断变大的圣诞老人,就像...

使用Python开发windows GUI程序入门实例

今天终于可以用wxPython开发GUI程序了,非常高兴。把其中的一些注意点写下来以供参考。在windows XP平台下,首先需要做以下环境的配置: 1. 首先是安装python ,安装...

Pytorch加载部分预训练模型的参数实例

前言 自从从深度学习框架caffe转到Pytorch之后,感觉Pytorch的优点妙不可言,各种设计简洁,方便研究网络结构修改,容易上手,比TensorFlow的臃肿好多了。对于深度学习...