threading模块中的对象

  • 其中除了Thread对象以外,还有许多跟同步相关的对象
  • threading模块支持守护线程的机制

Thread对象

直接调用法

import threading
import time def sayhi(num): #定义每个线程要运行的函数 print("running on number:%s" %num) time.sleep(3) if __name__ == '__main__': t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例
t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例 t1.start() #启动线程
t2.start() #启动另一个线程 print(t1.getName()) #获取线程名
print(t2.getName())

继承类方式

import threading
import time class MyThread(threading.Thread):
def __init__(self,num):
threading.Thread.__init__(self)
self.num = num def run(self):#定义每个线程要运行的函数 print("running on number:%s" %self.num) time.sleep(3) if __name__ == '__main__': t1 = MyThread(1)
t2 = MyThread(2)
t1.start()
t2.start()

 注意:当要启动这个线程时,只会去调用这个类的run方法,因此,在定义子类时,一定要去重写父类的run方法,不然在线程启动后,该线程不会做任何事情。

join和daemon问题

  • join:为了让主线程等待子线程结束。
  • daemon:将线程设置为守护线程,该线程就会变成设置其为守护线程的线程的“仆人”,当其“主人”要退出时,其不管自己的任务是否完成,都会跟着“主人一起退出”。

Some threads do background tasks, like sending keepalive packets, or performing periodic garbage collection, or whatever. These are only useful when the main program is running, and it's okay to kill them off once the other, non-daemon, threads have exited.

Without daemon threads, you'd have to keep track of them, and tell them to exit, before your program can completely quit. By setting them as daemon threads, you can let them run and forget about them, and when your program quits, any daemon threads are killed automatically.

#_*_coding:utf-8_*_
__author__ = 'Alex Li' import time
import threading def run(n): print('[%s]------running----\n' % n)
time.sleep(2)
print('--done--') def main():
for i in range(5):
t = threading.Thread(target=run,args=[i,])
t.start()
t.join(1)
print('starting thread', t.getName()) m = threading.Thread(target=main,args=[])
m.setDaemon(True) #将main线程设置为Daemon线程,它做为程序主线程的守护线程,当主线程退出时,m线程也会退出,由m启动的其它子线程会同时退出,不管是否执行完任务
m.start()
m.join(timeout=2)
print("---main thread done----")

Lock对象(线程锁--互斥锁Mutex

线程锁与GIL的区别

  很多人都不明白python已经有了一个GIL了,怎么还搞一个线程锁。先给个图:

首先要明确,线程锁是用户级别的锁机制,跟解释器的GIL没有任何关系,也不会互相有任何。接下来,大家要注意GIL的描述,它说的是“同一时刻只会有一个线程在cpu上执行”,这并不代表着这个占用cpu的线程之行完后再去执行另一个线程(如果是这样的话,那就不存在多线程的说法了),那么线程很可能会在执行任务中,被打断,让出cpu(python的线程机制是调用的c的线程接口,即原生线程的调用,因此,调度方案是由操作系统决定的)。

即然是这样的,回到用python创建的线程中。上图中,红色的线程的任务是做“加1”操作,由于这个“加一”的操作并不是“原子操作”,所以,在执行时,很可能被打断。如果这时打断红色的线程是蓝色的线程,它同样是利用count(共享资源),那么由于红色的进程没有完成其任务,所以,蓝色的进程读到的count的跟红色的进程读到的值一样(即count=0)。这时,蓝色的线程正常执行,完成“加1”任务(count=1),之后,红色的进程再重新恢复执行,但当下,其拿到的“count=0”,然后完成“加1”任务,即这时“count=1”。

回过头了,我们起初想要的结果是“count=2”,而不是“count=1”。在这个过程中,我们是遵守GIL规则的,但是还是很可能会出现上述现象,这就是我说的,线程锁是用户级别的锁,跟GIL没有关系,我要考虑的业务逻辑是否需要做“原子操作”的问题,如果需要,就需要线程锁机制。

基本使用方法

import time
import threading def addNum():
global num #在每个线程中都获取这个全局变量
print('--get num:',num )
time.sleep(1)
lock.acquire() #修改数据前加锁
num -=1 #对此公共变量进行-1操作
lock.release() #修改后释放 num = 100 #设定一个共享变量
thread_list = []
lock = threading.Lock() #生成全局锁
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t) for t in thread_list: #等待所有线程执行完毕
t.join() print('final num:', num )

RLock(递归锁)

说白了就是要在大锁中再次添加锁的机制

基本使用方法

import threading,time

def run1():
print("grab the first part data")
lock.acquire()
global num
num +=1
lock.release()
return num
def run2():
print("grab the second part data")
lock.acquire()
global num2
num2+=1
lock.release()
return num2
def run3():
lock.acquire()
res = run1()
print('--------between run1 and run2-----')
res2 = run2()
lock.release()
print(res,res2) if __name__ == '__main__': num,num2 = 0,0
lock = threading.RLock()
for i in range(10):
t = threading.Thread(target=run3)
t.start() while threading.active_count() != 1:
print(threading.active_count())
else:
print('----all threads done---')
print(num,num2)

semaphore对象(信号量)

互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。

import threading,time

def run(n):
semaphore.acquire()
time.sleep(1)
print("run the thread: %s\n" %n)
semaphore.release() if __name__ == '__main__': num= 0
semaphore = threading.BoundedSemaphore(5) #最多允许5个线程同时运行
for i in range(20):
t = threading.Thread(target=run,args=(i,))
t.start() while threading.active_count() != 1:
pass #print threading.active_count()
else:
print('----all threads done---')
print(num)

timer对象

This class represents an action that should be run only after a certain amount of time has passed

Timers are started, as with threads, by calling their start() method. The timer can be stopped (before its action has begun) by calling thecancel() method. The interval the timer will wait before executing its action may not be exactly the same as the interval specified by the user.

def hello():
print("hello, world") t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed

Events对象

An event is a simple synchronization object;

the event represents an internal flag, and threads
can wait for the flag to be set, or set or clear the flag themselves.

event = threading.Event()

# a client thread can wait for the flag to be set
event.wait()

# a server thread can set or reset it
event.set()
event.clear()
If the flag is set, the wait method doesn’t do anything.
If the flag is cleared, wait will block until it becomes set again.
Any number of threads may wait for the same event.

通过Event来实现两个或多个线程间的交互,下面是一个红绿灯的例子,即起动一个线程做交通指挥灯,生成几个线程做车辆,车辆行驶按红灯停,绿灯行的规则。

import threading,time
import random
def light():
if not event.isSet():
event.set() #wait就不阻塞 #绿灯状态
count = 0
while True:
if count < 10:
print('\033[42;1m--green light on---\033[0m')
elif count <13:
print('\033[43;1m--yellow light on---\033[0m')
elif count <20:
if event.isSet():
event.clear()
print('\033[41;1m--red light on---\033[0m')
else:
count = 0
event.set() #打开绿灯
time.sleep(1)
count +=1
def car(n):
while 1:
time.sleep(random.randrange(10))
if event.isSet(): #绿灯
print("car [%s] is running.." % n)
else:
print("car [%s] is waiting for the red light.." %n)
if __name__ == '__main__':
event = threading.Event()
Light = threading.Thread(target=light)
Light.start()
for i in range(3):
t = threading.Thread(target=car,args=(i,))
t.start()

python多线程之threading模块的更多相关文章

  1. “死锁” 与 python多线程之threading模块下的锁机制

    一:死锁 在死锁之前需要先了解的概念是“可抢占资源”与“不可抢占资源”[此处的资源可以是硬件设备也可以是一组信息],因为死锁是与不可抢占资源有关的. 可抢占资源:可以从拥有他的进程中抢占而不会发生副作 ...

  2. python 多线程编程之threading模块(Thread类)创建线程的三种方法

    摘录 python核心编程 上节介绍的thread模块,是不支持守护线程的.当主线程退出的时候,所有的子线程都将终止,不管他们是否仍在工作. 本节开始,我们开始介绍python的另外多线程模块thre ...

  3. python多线程之Threading

    什么是线程? 线程是操作系统内核调度的基本单位,一个进程中包含一个或多个线程,同一个进程内的多个线程资源共享,线程相比进程是“轻”量级的任务,内核进行调度时效率更高. 多线程有什么优势? 多线程可以实 ...

  4. python多线程之threading、ThreadPoolExecutor.map

    背景: 某个应用场景需要从数据库中取出几十万的数据时,需要对每个数据进行相应的操作.逐个数据处理过慢,于是考虑对数据进行分段线程处理: 方法一:使用threading模块 代码: # -*- codi ...

  5. python 线程之 threading(四)

    python 线程之 threading(三) http://www.cnblogs.com/someoneHan/p/6213100.html中对Event做了简单的介绍. 但是如果线程打算一遍一遍 ...

  6. python 线程之 threading(三)

    python 线程之 threading(一)http://www.cnblogs.com/someoneHan/p/6204640.html python 线程之 threading(二)http: ...

  7. python并发编程之threading线程(一)

    进程是系统进行资源分配最小单元,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.进程在执行过程中拥有独立的内存单元,而多个线程共享内存等资源. 系列文章 py ...

  8. {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器

    Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...

  9. <python的线程与threading模块>

    <python的线程与threading模块> 一 线程的两种调用方式 threading 模块建立在thread 模块之上.thread模块以低级.原始的方式来处理和控制线程,而thre ...

随机推荐

  1. “全栈2019”Java多线程第二十五章:生产者与消费者线程详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  2. jzoj5805

    #include<bits/stdc++.h> using namespace std; int x,n,pp,ct[10000]; long double f[210][(1<&l ...

  3. Mysql分析-profile详解

    一.前言当我们要对某一条sql的性能进行分析时,可以使用它. Profiling是从 mysql5.0.3版本以后才开放的.启动profile之后,所有查询包括错误的语句都会记录在内.关闭会话或者se ...

  4. 推荐算法之 slope one 算法

    1.示例引入 多个吃货在某美团的某家饭馆点餐,如下两道菜: 可乐鸡翅: 红烧肉: 顾客吃过后,会有相关的星级评分.假设评分如下: 评分 可乐鸡翅 红烧肉 小明 4 5 小红 4 3 小伟 2 3 小芳 ...

  5. RabbitMQ交换机规则实例

    RabbitMQ Exchange分发消息时根据类型的不同分发策略有区别,目前共四种类型:direct.fanout.topic.headers .headers 匹配 AMQP 消息的 header ...

  6. Alamofire源码导读五:错误表示

    AFError is the error type returned by Alamofire. It encompasses a few different types of errors, eac ...

  7. Alamofire源码导读二:发起请求及内部加锁的逻辑

    以创建一个 DataRequest 为例子  发起请求 创建 SessionManager 顺带也创建了一个 SessionDelegate 持有一个urlSession,持有一个串行的 Dispa ...

  8. jq01--概述

    jq:jQuery,是一个JavaScript函数库,为了简化js开发与编码而封装的js库,是一个“写得更少,做得更多”的js函数库,为事件处理而特别设计的.现在我们来学习一下它. 1.jq库:为事件 ...

  9. Inno Setup入门(二十三)——Inno Setup类参考(9)

    今天就简单说一下ProgressBar. TNewProgressBar = class(TWinControl)   property Min: Longint; read write;   pro ...

  10. (转)MySQL字段类型详解

    MySQL字段类型详解 原文:http://www.cnblogs.com/100thMountain/p/4692842.html MySQL支持大量的列类型,它可以被分为3类:数字类型.日期和时间 ...