线程

常用的方法

import threading
import time def hello(name):
print('Hello %s' % name)
# 阻塞
time.sleep(5)
print('阻塞了') if __name__ == '__main__': t1 = threading.Thread(target=hello, args=('zhangsan',))
t2 = threading.Thread(target=hello, args=('lisi',))
t1.setName('first') # 设置线程名
start = time.time()
t1.start()
t2.start()
print('---------------')
print(t1.getName())
end = time.time()
print(end-start) # 计算时间

运算的结果如下,可以看到遇到阻塞是直接进行了异步操作,先执行了所有的操作,然后才进行了等待操作,最后结束了程序


import threading
import time def hello(name):
print('你好 %s' % name)
# 阻塞
time.sleep(5)
print('阻塞了') if __name__ == '__main__':
t1 = threading.Thread(target=hello, args=('李',))
t2 = threading.Thread(target=hello, args=('王',))
t1.setName('aaa') # 设置线程名
start = time.time()
t1.start()
t2.start()
t2.join()
print('---------------')
print(t1.getName()) # 获取线程名字
end = time.time()
print(end-start) # 计算时间

运算结果如下:可以看到等待了5秒后才往后执行,join()方法让线程变的毫无意义。

继承类的线程使用方法
import threading
import time class MyThread(threading.Thread):
def __init__(self, name):
super().__init__()
self.name = name
def run(self):
print('你好 %s' % self.name)
time.sleep(5)
print('阻塞了')
if __name__ == '__main__': t1 = MyThread('李')
t2 = MyThread('王')
start = time.time()
t1.start()
t2.start()
end = time.time()
print('运行时间 %s 秒' % (end - start)) # 计算时间

计算结果如下所示:

守护进程 setDaemon

不开的状态
import threading
import time def run(n):
print('你好 %s' % n)
time.sleep(2)
def main():
for i in range(5):
t = threading.Thread(target=run, args=(i,))
t.start()
m = threading.Thread(target=main)
m.start()
print('------运行结束-----')

运行结果:

开启后的状态
import threading
import time def run(n):
print('你好 %s' % n)
time.sleep(2)
print('我随后跑')
def main():
for i in range(5):
t = threading.Thread(target=run, args=(i,))
t.start()
m = threading.Thread(target=main)
m.setDaemon(True) # 开启True将主线程设置为守护进程,主线程结束那一刻,其他子线程会同时结束,不论是否执行完毕
m.start()
print('------运行结束-----')

运行结果如下:

可以看到主进程结束,直接程序结束,子进程压根都没运行。这就是守护进程

线程锁Lock

一个进程下可以启动多个线程,多个线程共享父进程的内存空间,每个线程可以访问同一份数据,所以当多个线程同时要修改同一份数据时,就会出现错误。

import threading
import time class MyThread(threading.Thread):
def run(self):
global num
time.sleep(1)
num = num + 1
msg = self.name + 'set num to' + str(num)
print(msg) num = 0
def test():
for i in range(5):
t = MyThread()
t.start() if __name__ == '__main__':
test()

运行结果出现了不可控,线程2没有增加到2,而线程5增加到了2,这是因为没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程运行的结果不可预期。这种现象称为“线程不安全”。

加锁
创建锁
lock = threading.Lock()
锁定资源
lock.acquire()
释放资源
lock.release()

import threading
import time class MyThread(threading.Thread):
def run(self):
global num
if lock.acquire():
time.sleep(1)
num = num + 1
msg = self.name + 'set num to' + str(num)
print(msg)
lock.release() num = 0
lock = threading.Lock()
def test():
for i in range(5):
t = MyThread()
t.start() if __name__ == '__main__':
test()

当多个线程都修改某一个共享数据的时候,需要进行同步控制。上锁之后,结果跟我们的预期完全一致。

互斥锁为资源引入一个状态:锁定/非锁定。某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

递归锁RLock

锁中包含锁


import threading def run1():
lock.acquire() # 小锁
global num
num += 1
lock.release()
return num
def run2():
lock.acquire() # 小锁
global num2
num2 += 1
lock.release()
return num2 def run3():
lock.acquire() # 大锁
res = run1()
res2 = run2()
lock.release()
print(res, res2) if __name__ == '__main__':
num, num2 = 0, 0
lock = threading.RLock() # 生成Rlock
for i in range(10):
t = threading.Thread(target=run3)
t.start() while threading.active_count() != 1: # 线程活动数量不是1,说明子线程还没运行完毕
pass
else:
print('运行结束')

semaphore信号量

同时允许一定数量的线程更改数据

import threading
import time def run(n):
semaphore.acquire()
time.sleep(1)
print('run the thread: %s' % n)
semaphore.release() if __name__ == '__main__':
semaphore = threading.BoundedSemaphore(3) # 设置最多允许3个线程同时运行
for i in range(20):
t = threading.Thread(target=run, args=(i,))
t.start()

3个3个分批次的出现

event事件

实现两个或多个线程间的交互

event.set() 会使event内部为真

event.clear() 会使event内部为假

event.isSet() 判断有没有被设定为真

如果event内部为真,则wait不阻塞,否则会阻塞

import threading

def start():
print('---start---1')
event.wait() # 阻塞
print('---start---2')
if __name__ == '__main__':
event = threading.Event()
t = threading.Thread(target=start)
t.start()
print(event.isSet())

运行结果,程序会阻塞在start1进行不下去

将event内部设置为真

import threading
def start():
print('---start---1')
event.wait() # 阻塞
print('---start---2')
if __name__ == '__main__':
event = threading.Event()
t = threading.Thread(target=start)
t.start()
event.set()
print(event.isSet())

运行结果会从阻塞变为畅通

Python中的线程详解的更多相关文章

  1. python中threading模块详解(一)

    python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...

  2. Python中time模块详解

    Python中time模块详解 在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. ...

  3. 第7.19节 Python中的抽象类详解:abstractmethod、abc与真实子类

    第7.19节 Python中的抽象类详解:abstractmethod.abc与真实子类 一.    引言 前面相关的章节已经介绍过,Python中定义某种类型是以实现了该类型对应的协议为标准的,而不 ...

  4. python中常用模块详解二

    log模块的讲解 Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适: logger提供了应用程序可以直接使用的接口API: handler将(logger创建的 ...

  5. 76.Python中F表达式详解

    F表达式是用来优化ORM操作数据库的. 举个例子:我们做口罩的公司要将所有员工的薪水增加2000元,如果按照正常的流程,应该是先从数据库中提取所有的员工的工资到Python内存中,然后使用Python ...

  6. python 中的unicode详解

    通过例子来看问题是比较容易懂的. 首先来看,下面这个是我新建的一个txt文件,名字叫做ivan_utf8.txt,然后里面随便编辑了一些东西. 然后来用控制台打开这个文件,同样也是截图: 这里就是简单 ...

  7. Python中time模块详解(转)

    在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. 在开始之前,首先要说明这几点: ...

  8. python 中model.py详解

    model详解 Django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表. 创建表 基本结构 from django.db import models # Creat ...

  9. python 中的map 详解

    python中的map函数应用于每一个可迭代的项,返回的是一个结果list.如果有其他的可迭代参数传进来,map函数则会把每一个参数都以相应的处理函数进行迭代处理.map()函数接收两个参数,一个是函 ...

随机推荐

  1. 初学vue----动画过渡transition简单部分

    使用动画效果要用transition包裹,transition(<trsnsition name="xx"><div></div></tr ...

  2. 公众号及H5支付

    本篇主要记录微信支付中公众号及H5支付全过程. 1|1准备篇 公众号或者服务号(并开通微信支付功能).商户平台中开通JSAPI支付.H5支付. 1|2配置篇 公众号或者服务号中 -------开发-- ...

  3. CocosCreator引擎修改与定制

    1.CCGame.js 修改部分数据脚本的加载时机,避免首屏卡顿 // Load game scripts var jsList = config[CONFIG_KEY.jsList]; if (js ...

  4. 关于C语言实现判断给定一个数,判断其是否是一个质数(素数)。

    Annotation:⒈我们需要明确0,1既不是质数,又不是合数.⒉其次我们需要知道一个质数,质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数.(自然数:自然数用以计量事物的件数或表示事 ...

  5. oracle左关联+号表示方式

    1.emp表和dept表 2.emp表中empno为8888的这条数据,没有部门编号,以emp表为主表,左关联查询部门信息sql语句如下: select * from emp e,dept d whe ...

  6. JavaScript 堆排序详解

    堆通常实现为全完二叉树,二叉堆一般分为两种:最大堆和最小堆.堆排序就是通过将数组转换成最大堆结构再进行排序. // 原理:把数组转换成最大堆来排序.把堆顶的最大数取出,将剩余的堆继续调整为最大堆,再次 ...

  7. jquery中使元素显示和隐藏方法之间的区别

    在实际的项目开发中,要使一个元素隐藏的方法有很多,比如css的多种属性和jquery的多种方法,虽然他们的作用都是使元素不可见,但是各个方法实现的原理是不一样的.下面主要介绍jquery各个元素隐藏方 ...

  8. OpenLDAP一登录系统就修改密码

    1:修改配置文件 在前面打开注释 moduleload ppolicy.la modulepath /usr/lib/openldap modulepath /usr/lib64/openldap   ...

  9. centos7以rpm方法装mysql5.7及大坑

    环境: CentOS Linux release 7.5.1804 (Core)   Mysql版本: MySQL-5.7.17-1.el6.x86_64.rpm-bundle.tar   下载地址( ...

  10. [转]python中pandas库中DataFrame对行和列的操作使用方法

    转自:http://blog.csdn.net/u011089523/article/details/60341016 用pandas中的DataFrame时选取行或列: import numpy a ...