标准流:浏览器对标签默认的布局方式就是标准流。 标准流布局原则:
块级标签: a、块级标签一个占一行(不管标签的宽度是否是浏览器宽度) b、默认宽度是父标签的宽度,默认高度是内容的高度。 c、直接设置宽高有效
行内标签: a、多个行内标签可以一行显示。 b、默认宽高是内容的宽高。 c、直接设置宽高无效。
行内块标签: a、多个行内块标签可以在一行显示。 b、默认宽高是内容的宽高。 c、直接设置宽高有效。
display属性:转换标签的性质 block:块级 inline:行内 inline-block:行内块
注意:行内块和其他标签之间默认会有个间隙,而且无法消除,所以一般不建议使用。
通过给float属性赋值为 left 或者 right 来让标签浮动。浮动会让标签脱流,脱流后原来的标准流布局方式不适用了。
float:left;
按照浏览器的左上角为起点。
float:right
按照浏览器的右上角为起点。
浮动的目的:让竖着显示的可以横着来(针对块)
浮动的效果: 一行可以显示多个;默认的宽高是内容的大小;可以设置宽度和高度
注意事项: a、如果同一级的标签,后面的需要浮动,前面的也需要浮动,否则可能会出现一些显示问题。 b、浮动的标签不占位置,不浮动的占位置。
利用浮动产生文字环绕效果 结论:被环绕的标签浮动,文字对应的标签不浮动。
清除浮动:不是将标签的浮动给去掉,而是清除因为浮动而产生的高度塌陷的问题。
高度塌陷:在文档流中,父元素的高度默认是被子元素撑开的,也就是子元素多高,父元素就多高。 但是当为子元素设置浮动以后,子元素会完全脱离文档流,此时将会导致子元素无法撑起父元素的高度,导致父元素的高度塌陷。 由于父元素的高度塌陷了,则父元素下的所有元素都会向上移动,这样将会导致页面布局混乱。
高度塌陷产生原因:父标签不浮动,子标签浮动,并且不设置父标签的高度,就会产生高度塌陷问题。
解决方案: 1、在后面添加一个div空盒子,设置样式为clear:both
<div id="" style="clear: both;">
</div>
2、给父标签添加样式,设置overflow的值为hidden。
3、万能清除法
#father:after{
display: block;
clear: both;
content: '';
visibility: hidden;
height: 0;
}
#father{
zoom: 1;
}
CSS中可以通过left,right,bottom,top属性来设置标签上下左右的距离。但是要通过position属性设置参考对象。
absolute:相对第一个非static/initial(默认值)父标签进行定位。
relative:相对于自己在标准流中的位置来定位。(当标签本身不希望去定位,只是想让自己的子标签可以相对自己定位时使用。)
fixed:相对于浏览器定位。(滚动时位置相对于浏览器不变)
sticky:当网页的内容不超过一屏(不滚动),按照标准流定位;超过一屏就相对浏览器定位。
initial:默认值,没有相对定位。
技巧:当遇到某个方向的定位无效时,可以尝试让标签浮动然后定位。
html中所有可见的标签都是一个盒子模型:包括长和宽决定的content、padding、border、margin。 其中content、padding、border是可见的,margin是不可见的。
表单标签 – form
表单标签是用来收集用户信息的,是一个容器。 可以将收集到的数据,通过method对应的方式,去发送请求。(发送给action对应的接口)
单标签
A、文本输入框和密码输入框(type = text,password)
<form action="" method="post">
<!--a、文本输入框-->
<span>账号</span>
<input type="text" name="username" id="" value="账号" placeholder="请输入账号" maxlength="8"/>
<span>密码</span>
<input type="password" name="passwd" id="password" value="" placeholder="请输入密码" />
<input type="submit" value="提交"/>
</form>
(1)、type属性:决定input标签的样式。text(默认):文本输入框;password:用于输入密码隐藏。 (2)、name属性:区分不同的input对应的值,对标签的显示没有影响。 (3)、value属性:input标签中的值,提交input中的数据给服务器的时候,是以name = value来提交的。(文本输入框中输入的内容就是value的值)。 (4)、placeholder属性:占位符(输入框的提示信息)。 (5)、maxlength属性:约束输入最大位数。
B、单选按钮(type = radio)
<input type="radio" name="sex" value="boy" checked="" /><span>男</span>
<input type="radio" name="sex" value="girl" /><span>女</span>
(1)、value:设置这个按钮选中提交的值。 (2)、name值:如果多个按钮只能选中一个,那么这些按钮的name值必须一致。 (3)、一组(name值一样)单选按钮在提交的时候只提交被选中的按钮的name和value值。 (4)、checked:默认初始选择一个。
C、复选框(type = checkbox)
<form action="" method="post">
<input type="checkbox" name="habby" value="篮球"/><span>篮球</span>
<input type="checkbox" name="habby" value="乒乓球"/><span>乒乓球</span>
<input type="checkbox" name="habby" value="羽毛球"/><span>羽毛球</span>
<input type="checkbox" name="habby" value="网球"/><span>网球</span>
</form>
同一组name值必须一样
D、普通按钮(type = button)
<input type="button" name="" value="登录" />
E、提交按钮(type = submit)
<input type="submit" name="" id="" value="提交" />
自动将当前form中设置了name属性的input标签的值,通过method的方式,提交给action对应的接口。
F、重置按钮(type = reset)
<input type="reset" name="" id="" value="重置" />
将form标签中的input标签所有值恢复初始状态。
G、文件域(type = file)
<input type="file" name="" id="" value="" />
选择本地文件
下拉菜单标签 – select 下拉和多行文本域可以放在form标签里面用于收集信息。
<select name="city">
<optgroup label="四川省">
<option value="成都" selected="selected">成都</option>
<option value="德阳">德阳</option>
<option value="眉山">眉山</option>
<option value="乐山">乐山</option>
<option value="泸州">泸州</option>
</optgroup>
<optgroup label="广东省">
<option value="深圳">深圳</option>
<option value="广州">广州</option>
<option value="中山">中山</option>
<option value="佛山">佛山 </option>
<option value="东莞">东莞</option>
</optgroup>
</select>
下拉菜单标签 – select 一个select标签对应一个下拉菜单,分组用optgroup属性设置,选项要通过option来列举。selected用来选择默认选项。
多行文本域 – textarea
<textarea name="message" maxlength="200" placeholder="输入你想写的文字" cols="40"></textarea>
(1)、name提交数据对应的名字。 (2)、rows:默认一屏的行数。 (3)、cols:默认的列数。 (4)、placeholder:设置占位符。 (5)、disabled:禁用。
div 和 span 标签是空白标签,没有语意。
块级标签:一个标签占一行
h1-6 , p , ol , table, hr
行内标签:一行可以多个标签
img , a , input , select , textarea
CSS是web标准中的表现标准,用来规定网页上内容的布局和样式(CSS又叫样式表)。 目前广泛使用的是CSS3。
A、内联样式表 将样式表写在标签的style属性中(每个可见的标签都有style属性)。
<p style="background-color: cornflowerblue;color: red;">这是CSS样式表</p>
B、内部样式表 将样式表写在 head标签的 style标签里面。
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
h1{
background-color: skyblue;
color: saddlebrown;
}
</style>
</head>
<h1>我是标题1</h1>
<h1>我是标题2</h1>
C、外部样式表 将样式表写在一个CSS文件中,然后再把head标签中通过 link标签导入。
<link rel="stylesheet" type="text/css" href="css/form.css"/>
注意:不管在什么情况下,内联样式表的优先级最高。内部和外部样式表执行越后,优先级越高。
(1)标签/元素选择器:直接将标签名作为选择器,同时选中网页中所有同类型的标签。
a{} --- 选中所有a标签
(2)id 选择器:通过在id属性值前面加#,就构成了id选择器。选中 id 等于对应值得标签。
id 属性:所有的标签都有 id 属性。
#p1{} --- 选中 id 值是 p1 的标签
(3)class选择器:通过在class 属性值前加 .(点) ,就构成了类选择器。选中class等于对应的值的标签。
<h1 class="c1">我是class选择器</h1>
.c1{} --- 选中所有class的值是c1的标签
(4)群组选择器:多个单独的选择器之间使用逗号隔开。选中所有的单独的选择器
a,p,#p1,.c1{} --- 选中所有对应的标签
(5)包含选择器:多个选择器之间使用空格隔开。依次往下寻找,直到最后一个选择器。
div .c1 p{} --- 选中div标签中的class值为c1标签中的p标签。
(6)通配符*:直接将*作为选择器。选中当前页面中所有的标签。
*{} --- 选中所有标签,包括body标签
(7)父子选择器:a>b{} (8)兄弟选择器:a~b{} (9)相邻兄弟选择器:a+b{} (10)属性选择器:a[b = c]
前面的元素选择器、id选择器、class选择器选中的都是标签。而伪类选择器选中的是标签的某个状态,一般使用于超链接和按钮等。
(1)、语法:
标签:状态{}
说明:
link:初始状态
visited:访问后的状态
active:被激活对应的状态(鼠标点击时)
hover:鼠标悬停在标签上的状态
focus:成为焦点(输入框中用的比较多)
标签:可以通过不同的选择器去选中。
(2)、爱恨原则:LoVeHAte – 先爱后恨 如果想要给一个标签同时给link\visited\hover\active中的两个或者两个以上的状态设置样式,必须遵守爱恨原则。不遵守可能会出问题。
(1)、就近原则
(2)、具体性原则
id>类>标签[…]>标签>通配符
(3)、重要性原则
color:red !important;
通过不同的选择器选中了同一个标签,谁的优先级高就谁有效。权重值大 –> 高优先级 权重值相同时,后写的选择器优先级高。
权重值 伪类选择器:0001 通配符:0001 元素选择器:0001 class选择器:0010 id选择器:0100 群组选择器:看单独每一个的权重。 包含选择器:多个选择器的权重和。
注意:不管选择器的权重有多高,内联样式的优先级都是最高的。
web前端的内容:HTML、CSS、JavaScript
web标准(万维网指定的)中规定HTML是结构标准,CSS是表现标准,JS是行为标准。
HTML又叫超文本标记语言(不同于编程语言)
H5: 狭义 –> 指html第5个大的版本 广义 –> 指的是 html5 + CSS3 +JavaScript
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
内容可见
</body>
</html>
网页中的内容就是通过HTML中不同的标签(标记)来确定。
标签语法:
a、双标签(常规标签):
<标签名 属性1=属性值1 属性2=属性值2 ……> 标签内容 </标签名>
b、单标签:
<标签名 属性1=属性值1 属性2=属性值2 ……>
或者
<标签名 属性1=属性值1 属性2=属性值2 ……/>
说明: <>, </>:固定写法,html中所有的标签都是写在<>中的。 标签名:不是随便命名的,而是一些固定的值。例如p标签,a标签,h1标签…… 属性:属性放在开始标签中,属性名和值之间用 = 连接,多个属性之间用空格隔开。属性可以是自定义属性,也可以是标签自带属性。 标签内容:双标签才存在标签内容,标签内容可以是任何东西。 </>:结束标签,单标签没有一个单独的结束标签。
HTML语法中大小写不敏感。 文件名命名要求:由字母和数字组成,但是数字不开头,一般用小写字母。网站首页一般是 index.html
<!DOCTYPE html>:用来说明当前html文件使用的版本。其中 html 代表 html5 。
head标签:里面的内容一般是不可见的,一般做一些网页设置性的操作。
head标签中的内容:meta标签、title标签、link标签、style标签、script标签、base标签
body标签:里面的内容一般是可见的,是网页中的主体
h1标签
范围:h1 - h6
<h1>我是标题1</h1>
段落
<p>文字段落</p>
注意:html中的文字是不会因为手动的回车和空格以及缩进产生空白效果。
可以通过一些特殊的符号来产生一些特殊的效果:
\ –> 空格
<br/> –> 强制换行
<hr> –> 水平线
文字效果
列表 ul–无序列表
<ul>
<li>语文</li>
<li>数学</li>
<li>英语</li>
</ul>
ol–有序列表
<ol>
<li>北京</li>
<li>成都</li>
<li>大连</li>
</ol>
dl–自定义列表
<dl>
<dt>A</dt>
<!--对列表进行分组-->
<dd>1</dd>
<!--分组下的内容-->
<dd>2</dd>
<dt>B</dt>
<dd>one</dd>
<dd>two</dd>
</dl>
图片 img标签 –> 单标签
<img src="img/guidao.jpg" title="鬼刀" alt="加载失败"/>
<!--
src属性:图片地址
title属性:鼠标放上去显示信息
alt属性:用来设置图片加载失败的时候的提示信息
-->
超链接
href属性
<a href="http://www.baidu.com">百度</a>
<a href="">刷新</a>
<a href="#1">第一张</a>
<!--
href属性:跳转到目标对应的地址
如果href属性值为空,对应是刷新功能
选择器:可以跳转到对应位置(在之前标签设置id值)
-->
target属性
<a target="_self"></a>
<!--默认当前页面刷新出指定内容-->
<a target="_blank"></a>
<!--创建一个新的页面,在新的页面中刷新出指定内容-->
表格 table标签、tr标签、td标签、th标签
快捷创建表格:table>trn>trm 然后tab补全。 创建一个n行m列的表格
表格边框为1处理:边框设置为0,表格颜色和单元格颜色不同即可。
<table border="1" bordercolor="red" bgcolor="aquamarine" align="center" cellspacing="1" cellpadding="1">
<tr><th>成绩表</th></tr>
<tr>
<td>姓名</td>
<td>成绩</td>
<td>是否留级</td>
</tr>
<tr>
<td>星辰</td>
<td>90</td>
<td>否</td>
</tr>
<tr>
<td>云落</td>
<td>85</td>
<td>否</td>
</tr>
</table>
<!--
table:表格整体
border:表格边框宽度
bordercolor:表格颜色
bgcolor:背景颜色
cellspacing:单元格和单元格之间的间隙
cellpadding:单元格和内容之间的间隙
tr:行
td:单元格
th:表头
align:设置对齐方式(可以作用于表,行,单元格)
-->
复杂表格的过程: 先确定表格最多有多少行,再确定每行有多少个单元格再确定每个单元格是否有合并现象,如果有就设置单元格的colspan属性,如果有列合并就设置单元格rowspan属性。
web前端的内容:HTML、CSS、JavaScript
web标准(万维网指定的)中规定HTML是结构标准,CSS是表现标准,JS是行为标准。
HTML又叫超文本标记语言(不同于编程语言)
H5: 狭义 –> 指html第5个大的版本 广义 –> 指的是 html5 + CSS3 +JavaScript
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
内容可见
</body>
</html>
网页中的内容就是通过HTML中不同的标签(标记)来确定。
标签语法:
a、双标签(常规标签):
<标签名 属性1=属性值1 属性2=属性值2 ……> 标签内容 </标签名>
b、单标签:
<标签名 属性1=属性值1 属性2=属性值2 ……>
或者
<标签名 属性1=属性值1 属性2=属性值2 ……/>
说明: <>, </>:固定写法,html中所有的标签都是写在<>中的。 标签名:不是随便命名的,而是一些固定的值。例如p标签,a标签,h1标签…… 属性:属性放在开始标签中,属性名和值之间用 = 连接,多个属性之间用空格隔开。属性可以是自定义属性,也可以是标签自带属性。 标签内容:双标签才存在标签内容,标签内容可以是任何东西。 </>:结束标签,单标签没有一个单独的结束标签。
HTML语法中大小写不敏感。 文件名命名要求:由字母和数字组成,但是数字不开头,一般用小写字母。网站首页一般是 index.html
<!DOCTYPE html>:用来说明当前html文件使用的版本。其中 html 代表 html5 。
head标签:里面的内容一般是不可见的,一般做一些网页设置性的操作。
head标签中的内容:meta标签、title标签、link标签、style标签、script标签、base标签
body标签:里面的内容一般是可见的,是网页中的主体
h1标签
范围:h1 - h6
<h1>我是标题1</h1>
段落
<p>文字段落</p>
注意:html中的文字是不会因为手动的回车和空格以及缩进产生空白效果。
可以通过一些特殊的符号来产生一些特殊的效果:
\ –> 空格
<br/> –> 强制换行
<hr> –> 水平线
文字效果
列表 ul–无序列表
<ul>
<li>语文</li>
<li>数学</li>
<li>英语</li>
</ul>
ol–有序列表
<ol>
<li>北京</li>
<li>成都</li>
<li>大连</li>
</ol>
dl–自定义列表
<dl>
<dt>A</dt>
<!--对列表进行分组-->
<dd>1</dd>
<!--分组下的内容-->
<dd>2</dd>
<dt>B</dt>
<dd>one</dd>
<dd>two</dd>
</dl>
图片 img标签 –> 单标签
<img src="img/guidao.jpg" title="鬼刀" alt="加载失败"/>
<!--
src属性:图片地址
title属性:鼠标放上去显示信息
alt属性:用来设置图片加载失败的时候的提示信息
-->
超链接
href属性
<a href="http://www.baidu.com">百度</a>
<a href="">刷新</a>
<a href="#1">第一张</a>
<!--
href属性:跳转到目标对应的地址
如果href属性值为空,对应是刷新功能
选择器:可以跳转到对应位置(在之前标签设置id值)
-->
target属性
<a target="_self"></a>
<!--默认当前页面刷新出指定内容-->
<a target="_blank"></a>
<!--创建一个新的页面,在新的页面中刷新出指定内容-->
表格 table标签、tr标签、td标签、th标签
快捷创建表格:table>trn>trm 然后tab补全。 创建一个n行m列的表格
表格边框为1处理:边框设置为0,表格颜色和单元格颜色不同即可。
<table border="1" bordercolor="red" bgcolor="aquamarine" align="center" cellspacing="1" cellpadding="1">
<tr><th>成绩表</th></tr>
<tr>
<td>姓名</td>
<td>成绩</td>
<td>是否留级</td>
</tr>
<tr>
<td>星辰</td>
<td>90</td>
<td>否</td>
</tr>
<tr>
<td>云落</td>
<td>85</td>
<td>否</td>
</tr>
</table>
<!--
table:表格整体
border:表格边框宽度
bordercolor:表格颜色
bgcolor:背景颜色
cellspacing:单元格和单元格之间的间隙
cellpadding:单元格和内容之间的间隙
tr:行
td:单元格
th:表头
align:设置对齐方式(可以作用于表,行,单元格)
-->
复杂表格的过程: 先确定表格最多有多少行,再确定每行有多少个单元格再确定每个单元格是否有合并现象,如果有就设置单元格的colspan属性,如果有列合并就设置单元格rowspan属性。
掌握: (1)、数字、字符串、布尔值的缓存 (2)、垃圾回收机制中的引用计数机制
python中所有的数据都是对象,所有的变量都是对象的引用。
python对数字、字符串和布尔对象进行缓存,让不同的变量赋同样值的这些对象,给得地址是同样的地址。
总结: 1、给一个变量赋值的时候,赋的是数字、字符串、布尔的时候,会先在缓存中看是否存在这个值,若有直接将值对应的地址赋给变量。没有就在缓存中开辟空间存储数据,然后返回地址。 2、给一个变量赋值的时候,赋的是除了数字、字符串、布尔以外的值,就直接在内存中开辟空间存储值,返回地址。
一个变量存了一个对象的地址,那么这个变量就是这个对象的引用。
C的内存管理机制:手动 java/oc/python等:拥有一套属于自己的自动内存管理机制。
1、python通过垃圾回收机制来对内存进行管理的:不定时对程序中的对象进行检测,看是否需要回收(将对象的内存释放)。看是否需要回收旧看对象的引用计数是否为0,为0就回收。
2、引用计数 python中的每个对象在创建的时候就会有一个属性叫引用计数,对应的值是 0 。当对象被引用一次,其引用计数就会加 1 。 当对象的引用减少一个,其引用计数就会减 1 。
from sys import getrefcount
object1 = [1, 2]
object2 = object1
a = [object1, 2]
print(getrefcount(object1)) #查看引用计数
# getrefcount函数本身会对查看的对象进行一次引用
4
垃圾回收机制并不是一旦产生引用计数为 0 的对象就马上回收。而是不定时的对整个程序中的所有对象进行检测,检测对象为 0 才回收。
检测时间:当当前程序所有的对象引用计数变化的次数达到它的阈值才会对对象进行检测。
import gc
# 获取垃圾回收临界值
print(gc.get_threshold())
# 修改垃圾回收临界值
print(gc.set_threshold(500, 10, 10))
python的垃圾回收机制能够自动解决因为循环引用而导致的内存泄漏问题。
python里面自动解决循环引用问题引用的其他的引用对象
检测的时候如果对象(object_i)的引用计数不是0,就备份引用计数值(count_i),去找到引用对象的对象(object_j),然后将(object_j)的引用计数(count_j)减1,如果(count_j)减1后的值是0,那么(count_i)的值就减1,如果减完后的(count_i)的值也是0,那么(object_j)也销毁。
进程1:正在运行的一个程序,每个进程相互独立,并且运行在其专用且受保护的内存空间里面的。
线程:一个进程要想执行任务,必须得有线程(每个进程至少有一个线程),一个进程所有任务都在线程中执行。
主线程:每个进程默认有一个线程,这个线程叫主线程。默认情况下,所有的代码都是在主线程中执行的。
子线程:一个进程可以有多个线程。除了主线程以外,其他线程需要手动添加。
多线程原理: 同一时间,CPU只能处理一条线程,只有1条线程在工作。多线程并发执行,其实就是CPU快速的在多线程之间调度(切换),当CPU调度线程的时间足够快,就造成了多线程并发执行的假象。
使用情况: 让多个任务同时执行。
补充: a、打印当前时间
import datetime
datetime.datetime.now()
b、延时
import time
time.sleep(s)
python中内置模块 threading,用来支持多线程。Thread类的对象就是线程对象,需要线程的时候,就创建这个类或者这个类的子类对象。
import threading
获取当前线程对象 »> 用于测试
threading.current_thread()
t1 = threading.Thread(target=download, args=('终结者',))
"""
target:需要在子线程中调用的函数的函数名,子线程中执行的任务就是函数里面的代码。
args:函数对应的参数值(元组)
返回值:创建好的线程对象
"""
t1.start()
效果:
import threading
import datetime
import time
#模拟下载两个电影
def download(file):
print('开始下载:', datetime.datetime.now())
# 线程阻塞2s
time.sleep(2)
print(file+'下载结束',datetime.datetime.now())
print(threading.current_thread())
t1 = threading.Thread(target=download, args=('终结者2',))
t1.start()
t2 = threading.Thread(target=download, args=('沉默的羔羊',))
t2.start()
download('终结者1')
开始下载: 2018-09-13 11:08:56.927703
开始下载: 2018-09-13 11:08:56.928703
开始下载: 2018-09-13 11:08:56.928703
终结者2下载结束 2018-09-13 11:08:58.927818
<Thread(Thread-1, started 2324)>
沉默的羔羊下载结束 2018-09-13 11:08:58.928818
<Thread(Thread-2, started 5908)>
终结者1下载结束 2018-09-13 11:08:58.928818
<_MainThread(MainThread, started 5852)>
from threading import Thread
import datetime
import time
class DownLoadThread(Thread):
def __init__(self, file):
super().__init__()
self.file = file
def run(self):
print('开始下载:<%s> 时间:%s'%(self.file,datetime.datetime.now()))
time.sleep(5)
print('下载结束:<%s>! 时间:%s'%(self.file,datetime.datetime.now()))
print('===========')
t1 = DownLoadThread('沉默的羔羊')
t1.start()
print('+++++++++++')
结果:
===========
开始下载:<沉默的羔羊> 时间:2018-09-13 11:26:42.730664
+++++++++++
下载结束:<沉默的羔羊>! 时间:2018-09-13 11:26:47.730950
如果希望某个线程结束后才执行某个操作,就用线程对象调用 join()
start()会自动调用run()
from threading import Thread
import time
import datetime
import random
class DownLoadThread(Thread):
def __init__(self, file):
super().__init__()
self.file = file
def run(self):
print(self.file+' 开始下载', datetime.datetime.now())
time.sleep(random.randint(5,15))
print(self.file+' 下载结束', datetime.datetime.now())
t1 = DownLoadThread('美丽人生')
t2 = DownLoadThread('怦然心动')
start = time.time()
t1.start()
t2.start()
#t1,t2都结束才执行
t1.join() #后面的代码在t1对应的线程结束后才执行
t2.join() #后面的代码在t1对应的线程结束后才执行
end = time.time()
print(end - start)
结果:
美丽人生 开始下载 2018-09-13 13:36:42.334387
怦然心动 开始下载 2018-09-13 13:36:42.334387
美丽人生 下载结束 2018-09-13 13:36:49.334787
怦然心动 下载结束 2018-09-13 13:36:50.336844
8.00445818901062
尽量避免多个线程对同一个数据进行操作
解决方法:对相关代码加锁,让同一时间只有能有一个线程进行操作,释放后,才能让其它线程操作
锁: 同步锁(RLock) 和 互斥锁(Lock)– 了解
from threading import Lock
self.lock = Lock()
# 一般写在__init__方法中
self.lock.acquire()
# 线程操作前
self.lock.release()
# 线程操作后
实例:
"""__author__=Deathfeeling"""
import time
from threading import Thread, Lock
class Account():
"""账号类"""
def __init__(self, balance):
self.balance = balance
# 创建锁对象
self.lock = Lock()
def save_money(self, amount):
"""存钱"""
print('开始存钱')
# 加锁
self.lock.acquire()
old_amount = self.balance
time.sleep(2)
self.balance = old_amount + amount
print('存钱成功!最新余额是:',self.balance)
# 解锁
self.lock.release()
def get_money(self, amount):
"""取钱"""
self.lock.acquire()
print('开始取钱')
old_amount = self.balance
if old_amount < amount:
print('余额不足')
return
time.sleep(2)
self.balance = old_amount - amount
print('取钱成功!最新余额是:', self.balance)
self.lock.release()
def show_balance(self):
print('当前余额:', self.balance)
account = Account(1000)
# account.save_money(200)
# account.get_money(100)
# account.show_balance()
t1 = Thread(target=account.save_money, args=(200,))
t2 = Thread(target=account.save_money, args=(300,))
t1.start()
t2.start()
结果:
开始存钱
开始存钱
存钱成功!最新余额是: 1200
存钱成功!最新余额是: 1500