Python学习——Python线程
一、线程创建
#方法一:将要执行的方法作为参数传给Thread的构造方法
import threading
import time def show(arg):
time.sleep(2)
print('thread' + str(arg)) for i in range(10):
t = threading.Thread(target=show,args=(i,))
time.sleep(2)
t.start() #方法2:从Thread继承,并重写run()
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()
time.sleep(3)
t2.start()
注解:
Thread(group=None,target=None,name=None,args=(),kwargs={})
group:线程组,目前还没有实现,库引用时提示必须是None
target:要执行的方法
name:线程名
args/kwargs:要传入方法的参数,args和kwargs两个参数其实是二选一
#实例方法
isAlive():返回线程是否在运行
get/setName(name):获取/设置线程名
is/setDaemon(bool):获取/设置是否守护线程。初始值从创建该线程的线程继承,当没有非守护线程仍在运行时,程序将终止
start():启动线程
join([timeout]):阻塞当前上下文环境的线程。
二、Python多线程用法
import threading
from time import ctime,sleep def music(func):
for i in range(2):
print("I was listening to %s. %s" %(func,ctime()))
sleep(1)
def move(func):
for i in range(2):
print("I was at the %s! %s" %(func,ctime()))
sleep(5) threads = []
t1 = threading.Thread(target=music,args=('童话镇',))
threads.append(t1)
t2 = threading.Thread(target=move,args=('变形金刚',))
threads.append(t2) if __name__ == '__main__':
for t in threads:
t.setDaemon(True)
t.start() print("all over %s" %ctime())
注:
threads = []
t1 = threading.Thread(target=music,args=('童话镇',))
threads.append(t1)
创建了threads数组,创建线程t1,使用threading.Thread()方法,在这个方法中调用music方法target=music,args方法对music进行传参。 把创建好的线程t1装到threads数组中。
接着以同样的方式创建线程t2,并把t2也装到threads数组。
for t in threads:
t.setDaemon(True)
t.start()
最后通过for循环遍历数组。(数组被装载了t1和t2两个线程)
setDaemon()
setDaemon(True)将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起。子线程启动后,父线程也继续执行下去,当父线程执行完最后一条语句print "all over %s" %ctime()后,没有等待子线程,直接就退出了,同时子线程也一同结束。
serDeamon(False)(默认)前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,主线程停止。
运行结果:
I was listening to 童话镇. Thu Jun 22 23:23:07 2017
I was at the 变形金刚! Thu Jun 22 23:23:07 2017
all over Thu Jun 22 23:23:07 2017
从执行结果来看,子线程(muisc 、move )和主线程(print "all over %s" %ctime())都是同一时间启动,但由于主线程执行完结束,所以导致子线程也终止。
调整程序:
if __name__ == '__main__':
for t in threads:
t.setDaemon(True)
t.start() t.join() print "all over %s" %ctime()
加了join()方法,用于等待线程终止。join()的作用是,在子线程完成运行之前,这个子线程的父线程将一直被阻塞。
join()方法的位置是在for循环外的,也就是说必须等待for循环里的两个进程都结束后,才去执行主进程。
运行结果:
############运行结果###################
I was listening to 童话镇. Thu Jun 22 23:34:22 2017
I was at the 变形金刚! Thu Jun 22 23:34:22 2017
I was listening to 童话镇. Thu Jun 22 23:34:23 2017
I was at the 变形金刚! Thu Jun 22 23:34:27 2017
all over Thu Jun 22 23:34:32 2017
从结果的时间可以看出每首歌之间等待1秒,电影之间等待5秒,但是是同步进行的,总的时间为5秒
三、线程锁(LOCK,RLOCK)
由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 同一时刻允许一个线程执行操作。
Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。
可以认为Lock有一个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。
RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。
可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。
简言之:Lock属于全局,Rlock属于线程。
1,未使用锁
import threading
import time num = 0 def show(arg):
global num
time.sleep(1)
num +=1
print(num) for i in range(10):
t = threading.Thread(target=show, args=(i,))
t.start() print('main thread stop')
多次运行可能产生混乱。这种场景就是适合使用锁的场景。
2.使用锁
import threading
import time num = 0
lock = threading.RLock() # 调用acquire([timeout])时,线程将一直阻塞,
# 直到获得锁定或者直到timeout秒后(timeout参数可选)。
# 返回是否获得锁。
def show(arg):
lock.acquire()
global num
time.sleep(1)
num +=1
print(num)
lock.release() for i in range(10):
t = threading.Thread(target=show, args=(i,))
t.start() print('main thread stop')
加上锁后数字会一步步打印出来,不会因为拥堵而错乱的情况!
四、信号量(Semaphore)
互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。
import threading, time def run(n):
semaphore.acquire()
time.sleep(3)
print("run the thread: %s" % 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()
五、事件(event)
Python线程的事件主要用于主线程控制其他线程的执行,事件主要提供了三个方法:set、wait、clear
事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
clear:将“Flag”设置为False
set:将“Flag”设置为True
用threading.Event实现线程间的通讯
threading.Event使一个线程等待其他线程的通知,把这个Event传递到线程对象中,Event默认内置了一个标志,初始值为False。
一旦该线程通过wait()方法进入等待状态,直到另一个线程调用该Event的set()方法将内置标志设置为True时,
该Event会通知所有等待状态的线程恢复运行。
import threading def do(event):
print('start')
event.wait()
print('end') event_obj = threading.Event() for i in range(10):
t = threading.Thread(target=do, args=(event_obj,))
t.start() event_obj.clear() #继续阻塞 inp = input('input:')
if inp == 'true':
event_obj.set() # 唤醒
六、条件(condition)
所谓条件变量,即这种机制是在满足特定条件之后,线程才可以访问相关的数据!
它使用Condition类来完成,由于它也可以像锁机制那样用,所以它也有acquire方法和release方法,而且它还有wait,notify,notifyAll方法
一个简单的生产消费者模型,通过条件变量的控制产品数量的增减,调用一次生产者产品就是+1,调用一次消费者产品就会-1.
使用 Condition 类来完成,由于它也可以像锁机制那样用,所以它也有 acquire 方法和 release 方法,而且它还有
wait, notify, notifyAll 方法。
import threading
import time # 产品类
class Goods:
def __init__(self):
self.count = 0 def add(self, num=1):
self.count += num def sub(self):
if self.count >= 0:
self.count -= 1 def empty(self):
return self.count <= 0 # 生产者
class Producer(threading.Thread):
def __init__(self, condition, goods, sleeptime=1):
threading.Thread.__init__(self)
self.cond = condition
self.goods = goods
self.sleeptime = sleeptime def run(self):
cond = self.cond
goods = self.goods
while True:
# 锁住资源
cond.acquire()
goods.add()
print("产品数量:", goods.count, "生产者线程")
# 唤醒所有等待的线程 -> 其实就是唤醒消费者进程
cond.notifyAll()
# 解锁资源
cond.release()
time.sleep(self.sleeptime) # 消费者
class Consumer(threading.Thread):
def __init__(self, condition, goods, sleeptime=2):
threading.Thread.__init__(self)
self.cond = condition
self.goods = goods
self.sleeptime = sleeptime def run(self):
cond = self.cond
goods = self.goods while True:
time.sleep(self.sleeptime)
# 锁住资源
cond.acquire()
# 如无产品则让线程等待
while goods.empty():
cond.wait()
goods.sub()
print("产品数量:", goods.count, "消费者线程") g = Goods()
c = threading.Condition()
pro = Producer(c, g)
pro.start()
con = Consumer(c, g)
con.start()
七、定时器(Timer)
import threading
def SayHello():
print("hello world!")
t=threading.Timer(3,SayHello)
t.start()
def other_func():
print("let me running!")
t=threading.Timer(1,other_func)
t.start() if __name__ == "__main__":
SayHello()
other_func()
Python学习——Python线程的更多相关文章
- 1 python学习——python环境配置
1 python学习--python环境配置 要学习python语言,光看书看教程还是不好,得动手去写.当然,不管学习什么编程语言,最佳的方式还在于实践. 要实践,先得有一个Python解释器来解释执 ...
- Python学习---Python安装与基础1205
1.0. 安装 1.1.1. 下载 官网下载地址:https://www.python.org/downloads/release/python-352/ 1.1.2. 配置环境变量 因为在安装的时候 ...
- Python学习---Python下[元组]的学习
元组是不可变的, 用小括号()定义,而且一旦定义 ,不可变[类型是tuple] [元组看做一个整体,不可拆分,不可赋值,但可以全部重新赋值] 通过圆括号,用逗号分隔,常用在使语句或用户定义的函数能够安 ...
- python学习笔记——线程threading (二)重写run()方法和守护进程daemon()
1 run()方法 1.1 单个线程 在threading.Thread()类中有run()方法. from time import ctime,sleep import threading # 定义 ...
- python学习笔记——线程threading (一)
1 线程threading 1.1 基本概述 也被称为轻量级的进程. 线程是计算机多任务编程的一种方式,可以使用计算机的多核资源. 线程死应用程序中工作的最小单元 1.2 线程特点 (1)进程的创建开 ...
- Python学习---Python的异步IO[all]
1.1.1. 前期环境准备和基础知识 安装: pip3 install aiohttp pip3 install grequests pip3 install wheel pip3 install s ...
- Python学习--Python基础语法
第一个Python程序 交互式编程 交互式编程不需要创建脚本文件,是通过 Python 解释器的交互模式进来编写代码. linux上你只需要在命令行中输入 Python 命令即可启动交互式编程,提示窗 ...
- python学习-python入门
开始学习python,开始记录. 第一个小程序:登陆系统 功能:1.通过文件名和密码导入用户名和密码~ 2.用户输入用户名和密码 3.将用户输入的用户名进行比对,先判断用户名是否在黑名单里面,如果在黑 ...
- Python学习:python网址收集
Python学习网址收集: 语法学习:http://www.cnblogs.com/hongten/tag/python/ http://www.liaoxuefeng.com ...
- python学习--python 连接SQLServer数据库(两种方法)
1. python 学习.安装教程参照: http://www.runoob.com/python/python-tutorial.html 2. 集成开发环境 JetBrains PyCharm C ...
随机推荐
- jquery筛选数组之grep、each、inArray、map的用法及遍历son对象(转)
grep [传入的参数为返回bool类型的函数] <script type='text/javascript' src="/jquery.js"></script ...
- Windows下 Robhess SIFT源码配置
Robhess OpenSIFT 源码下载:传送门 为了进一步学习SIFT,选择论文就着代码看,在VS2013.OpenCV2.4.13下新建项目,跑一跑经典之作.由于将代码和Opencv配置好后还会 ...
- if-else 重构
最近发现自己写的代码if else太多了,有时候自己回头看都要重新捋逻辑,很不好.决定深入理解下if else重构. 中心思想: ①不同分支应当是同等层次,内容相当. ②合并条件表达式,减少if语句数 ...
- Linux内存管理--基本概念【转】
转自:http://blog.csdn.net/myarrow/article/details/8624687 1. Linux物理内存三级架构 对于内存管理,Linux采用了与具体体系架构不相关的设 ...
- Linux中THIS_MODULE宏定义详解
一直都在耿耿于怀,这个THIS_MODULE到底是个什么玩意,linux内核中无处不在的东西.今天上网搜了一下,算是基本明白了.网上牛人写的已经比较详细,另外目前暂时没有时间往更深层次分析,所以直接贴 ...
- Graphql 相关 strapi -- Koa2
Graphql 相关资源: https://github.com/chentsulin/awesome-graphql graphql-apis : https://gi ...
- 使用Jyhon脚本和PMI模块监控WAS性能数据
使用Jyhon脚本和PMI模块监控WAS性能数据的优点有: 1.可以使用非交互的方式远程获取数据 2.不需要图形化模块支持 3.对各种was版本的兼容性较高 4.使用方便,官方自带 缺点也有很多: 1 ...
- 015_NGINX作为WebSocket Proxy的设置
产研那边有通过nginx代理进行长连接的需求,咱们都知道默认nginx只支持短连接的,使用长连接需要单独配置 一. websocket协议提供创建一种支持在server和client之前双向通信的we ...
- igmp组播测试环境搭建
2.4G无线组播测试环境搭建: (1)组播源: VLC 或者 pixstream (2)无线: 2.4G AP (3)客户端PC: VLC播放器 有线直连 无线2.4G PC(组播源pixstream ...
- Android手机刘海屏(附工具类)
工具类 根据VIVO.OPPO.华为官方文档,这里整理了一个刘海屏工具类,判断设备是否为刘海屏,其他厂商公布相关方法后也会在此更新. OPPO: /** * OPPO * * @param conte ...