线程与多线程高级篇

python——线程与多线程进阶

 之前我们已经学会如何在代码块中创建新的线程去执行我们要同步执行的多个任务,但是线程的世界远不止如此。接下来,我们要介绍的是整个threading模块。threading基于Java的线程模型设计。锁(Lock)和条件变量(Condition)在Java中是对象的基本行为(每一个对象都自带了锁和条件变量),而在Python中则是独立的对象,所以python的threading模块中还提供了Lock,Rlock,Condition,Event等常用类,它们在python中是独立于Tread模块的,但是却与线程紧密相关,不可分割。

  需要注意的是:python的线程中没有优先级、线程组,也不能被停止、暂停、恢复、中断,线程只能随着线程中的代码执行完毕而被销毁。查了n多资料之后终于接受了以上事实,个人觉得这是python的一个坑,导致了我在实现线程池的时候无法停止已经注入了方法且执行超时的线程。

threading模块提供的类:  
  Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, local.

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

threading模块常用类详解

Thread类:我们使用Thread类来创建新的线程

  • start            线程准备就绪,等待CPU调度
  • setName      为线程设置名称
  • getName      获取线程名称
  • setDaemon  设置为后台线程或前台线程(默认)
                      如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
                      如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
  • join             逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
  • run             线程被cpu调度后执行Thread类对象的run方法

Lock类和Rlock类:由于线程之间随机调度:某线程可能在执行n条后,CPU接着执行其他线程。为了多个线程同时操作一个内存中的资源时不产生混乱,我们使用锁

    • acquire   给线程上锁
    • release   给线程解锁

无论是lock还是rlock,提供的方法都非常简单,acquire和release。但是rlock和lock的区别是什么呢?RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的锁。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#  Author: Jason Wang
import threading
lock = threading.Lock() #Lock对象
lock.acquire()
lock.acquire()  #产生了死锁。
lock.release()
lock.release()   

import threading
rLock = threading.RLock()  #RLock对象
rLock.acquire()
rLock.acquire() #在同一线程内,程序不会堵塞。
rLock.release()
rLock.release()   

Condition类:条件变量对象能让一个线程停下来,等待其它线程满足了某个“条件”。如,状态的改变或值的改变。

  • acquire   给线程上锁
  • wait           wait方法释放当前线程占用的锁,同时挂起线程,直至被唤醒或超时(需timeout参数)。当线程被唤醒并重新占有锁的时候,程序才会继续执行下去。
  • notify     唤醒一个挂起的线程(如果存在挂起的线程)。注:notify()方法不会释放所占用的锁。
  • notifyall  调用这个方法将通知等待池中所有线程,这些线程都将进入锁定池尝试获得锁定。此方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。

  比较经典的例子是下面这个生产者与消费者的例子,这个例子网上一搜到处都是,这里简单解释一下这段代码的意义,代码中写了两个类,Consumer和Producer,分别继承了Thread类,我们分别初始化这两个类获得了c和p对象,并启动这两个线程。则这两个线程去执行run方法(这里与Thread类内部的调度有关),定义了producer全局变量和condition对象为全局变量,当producer不大于1时,消费者线程被condition对象阻塞,不能继续消费(这里是不再递减),当producer不小于10时,生产者线程被condition对象阻塞,不再生产(这里是不再累加),代码在下面,拿去执行,断点一下就明白了。

import threading
import time
condition = threading.Condition()
products = 0

class Producer(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global condition, products
        while True:
            if condition.acquire():
                if products < 10:
                    products += 1;
                    print("Producer(%s):deliver one, now products:%s" %(self.name, products))
                    condition.notify()
                else:
                    print("Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products))
                    condition.wait();
                condition.release()
                time.sleep(2)

class Consumer(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global condition, products
        while True:
            if condition.acquire():
                if products > 1:
                    products -= 1
                    print("Consumer(%s):consume one, now products:%s" %(self.name, products))
                    condition.notify()
                else:
                    print("Consumer(%s):only 1, stop consume, products:%s" %(self.name, products))
                    condition.wait();
                condition.release()
                time.sleep(2)

if __name__ == "__main__":
    for p in range(0, 2):
        p = Producer()
        p.start()

    for c in range(0, 10):
        c = Consumer()
        c.start()

Condition code

Event类:通用的条件变量。多个线程可以等待某个事件的发生,在事件发生后,所有的线程都会被激活。

  • event.wait(timeout)  当Flag为‘False’时,线程将被阻塞
  • clear                    将“Flag”设置为False
  • set                      将“Flag”设置为True
  • is_set                         返回当前‘Flag’

  这是一个比较关键的类,我在写线程池的时候看到python的threadpool模块也用到了。它的意义在于可以控制属于同一个线程类的多个实例化对象,让他们同时阻塞或者执行。配合队列来实现一个线程池非常好用。在接下里的博客中我们还要继续介绍。先放一个小例子在这里练练手,了解一下event的用法。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#  Author: Jason Wang

import threading

def do(event):
    print(‘start‘)
    event.wait() #执行对象weit方法,然后他们停下来,等待“Flag”为True
    print(‘execute‘)

event_obj = threading.Event() #创建事件的对象

for i in range(3):
    t = threading.Thread(target=do, args=(event_obj,)) #吧对象传到每个线程里面了~
    t.start()

event_obj.clear()  #设置"Flag"为Flase

inp = input(‘input:‘)
if inp == ‘true‘:
    event_obj.set()

#thread enent 就是这个3个方法的使用
##output
# start
# start
# start
# input:true
# execute
# execute
# execute

Thread Event Code

参考文献:

  python多线程学习小结:http://www.myexception.cn/perl-python/1688021.html

  python线程指南:http://www.cnblogs.com/huxi/archive/2010/06/26/1765808.html

  threading.RLock和threading.Lock:http://blog.sina.com.cn/s/blog_5dd2af0901012rad.html

  python的进程、线程与协程:http://www.cnblogs.com/wupeiqi/articles/5040827.html

时间: 2024-11-08 17:12:58

线程与多线程高级篇的相关文章

多线程下的进程同步(线程同步问题总结篇)

之前写过两篇关于线程同步问题的文章(一,二),这篇中将对相关话题进行总结,本文中也对.NET 4.0中新增的一些同步机制进行了介绍. 首先需要说明的是为什么需要线程功能同步.MSDN中有这样一段话很好的解释了这个问题: 当多个线程可以调用单个对象的属性和方法时,对这些调用进行同步处理是非常重要的.否则,一个线程可能会中断另一个线程正在执行的任务,使该对象处于一种无效状态. 也就说在默认无同步的情况下,任何线程都可以随时访问任何方法或字段,但一次只能有一个线程访问这些对象.另外,MSDN中也给出定

《C#网络编程高级篇之网页游戏辅助程序设计(扫描版)》

<C#网络编程高级篇之网页游戏辅助程序设计>通过编写C#网络编程语言中具有代表性的实例,向读者深入细致地讲解了如何利用C#语言进行网页游戏辅助程序设计.本书通过大量的代码引导读者一步步学习和掌握C#的网络应用编程的方法和网页游戏辅助程序的设计技术. <C#网络编程高级篇之网页游戏辅助程序设计>涉及的领域包括多线程编程技术.socket套接字编程.tcp协议编程.http协议编程.远程控制技术.木马技术.模拟键盘和鼠标技术.网页游戏辅助程序设计技术等. <C#网络编程高级篇之网

Java 编程之美:并发极速赛车平台出租编程高级篇

借用 Java 并发极速赛车平台出租haozbbs.comQ1446595067 编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了. 相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作的顺序是不可预期的. 并发编程相比 Java 中其他知识点学习起来门槛相对较高,学习起来比较费劲,从而导致很多人望而却步: 而无论是职场面试和高并发高流量的系统的实现却都还离不开并发编程,从而导致能够真正掌握并发编程的人才成为市场比较迫

Spark性能优化指南——高级篇

Spark性能优化指南--高级篇 [TOC] 前言 继基础篇讲解了每个Spark开发人员都必须熟知的开发调优与资源调优之后,本文作为<Spark性能优化指南>的高级篇,将深入分析数据倾斜调优与shuffle调优,以解决更加棘手的性能问题. 数据倾斜调优 调优概述 有的时候,我们可能会遇到大数据计算中一个最棘手的问题--数据倾斜,此时Spark作业的性能会比期望差很多.数据倾斜调优,就是使用各种技术方案解决不同类型的数据倾斜问题,以保证Spark作业的性能. 数据倾斜发生时的现象 绝大多数tas

秒杀多线程第一篇 多线程笔试面试题汇总 ZZ 【多线程】

http://blog.csdn.net/morewindows/article/details/7392749 系列前言 本系列是本人参加微软亚洲研究院,腾讯研究院,迅雷面试时整理的,另外也加入一些其它IT公司如百度,阿里巴巴的笔试面试题目,因此具有很强的针对性.系列中不但会详细讲解多线程同步互斥的各种“招式”,而且会进一步的讲解多线程同步互斥的“内功心法”.有了“招式”和“内功心法”,相信你也能对多线程挥洒自如,在笔试面试中顺利的秒杀多线程试题. ----------------------

秒杀多线程第一篇 多线程笔试面试题汇总

版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 系列前言 本系列是本人参加微软亚洲研究院,腾讯研究院,迅雷面试时整理的,另外也加入一些其它IT公司如百度,阿里巴巴的笔试面试题目,因此具有很强的针对性.系列中不但会详细讲解多线程同步互斥的各种“招式”,而且会进一步的讲解多线程同步互斥的“内功心法”.有了“招式”和“内功心法”,相信你也能对多线程挥洒自如,在笔试面试中顺利的秒杀多线程试题. -------------------------------------华丽的分割线

Linux C 程序设计多线程基础篇

   Linux C 程序设计多线程基础篇 题记:因为 Linux 网络入侵检测系统的设计与实现希望使用多线程,因此希望系统的学习一下 Linux C程序设计多线程的知识 注意事项:因为 pthraed 库不是 Linux 系统默认的库,因此在进行多线程开发的时候,需要加上头文件#include <pthread.h>,编译时要加参数 -lpthread;了:gcc thread.c -o thread -lpthread. 进程和线程: 进程是程序执行,资源分配的基本单位,每个进程都拥有自己

【转载】Spark性能优化指南——高级篇

前言 数据倾斜调优 调优概述 数据倾斜发生时的现象 数据倾斜发生的原理 如何定位导致数据倾斜的代码 查看导致数据倾斜的key的数据分布情况 数据倾斜的解决方案 解决方案一:使用Hive ETL预处理数据 解决方案二:过滤少数导致倾斜的key 解决方案三:提高shuffle操作的并行度 解决方案四:两阶段聚合(局部聚合+全局聚合) 解决方案五:将reduce join转为map join 解决方案六:采样倾斜key并分拆join操作 解决方案七:使用随机前缀和扩容RDD进行join 解决方案八:多

Java的线程和多线程教程

Java线程(Java Thread)是执行某些任务的一种轻量级进程.Java中的Thread类提供了多线程(multi-threading)功能,应用程序能够创建多个线程并同一时候执行. 在一个应用程序中,一般会有两种类型的线程-用户线程(user thread)和守护线程(daemon thread).当我们启动引用程序时,首先创建用户线程main,我们能够创建多个用户线程和守护线程.当全部的用户线程都运行完成时,JVM就会终止程序. 对不同的线程,我们能够设置对应的优先级,但并不意味着高优