Python3(基础|高级)语法实战(|多线程|多进程|线程池|进程池技术)|多线程安全问题解决方案
Python3操作MySQL8.XX创建表|CRUD基本操作
Python3操作SQLite3创建表主键自增长|CRUD基本操作
anaconda3最新版安装|使用详情|Error: Please select a valid Python interpreter
Python函数绘图与高等代数互融实例(一):正弦函数与余弦函数
Python函数绘图与高等代数互融实例(三):设置X|Y轴|网格线
Python函数绘图与高等代数互融实例(四):设置X|Y轴参考线|参考区域
Python函数绘图与高等代数互融实例(五): 则线图综合案例
介绍
开源包管理系统和环境管理系统 ,包括多种语言的包安装,运行,更新,删除,最重要的是可以解决包依赖问题支持语言包括 Python,R,Ruby,Lua,Scala,Java,JavaScript,C / C ++,FORTRAN
支持在Windows,macOS和Linux上运行
Conda可以构建不同的环境,同时可以对环境进行保存,加载和切换操作
conda包和环境管理器包含在所有版本的Anaconda和Miniconda中
一: 安装|下载anaconda
清华大学开源软件镜像站:下载安装包Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
二: 添加镜像源
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/bioconda/
conda config --add channels https://mirrors.bfsu.edu.cn/anaconda/cloud/bioconda/
conda config --add channels https://mirrors.bfsu.edu.cn/anaconda/cloud/conda-forge/
conda config --add channels https://mirrors.bfsu.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.bfsu.edu.cn/anaconda/pkgs/main/下面这个我没用过, 可以添加一下试试看.
conda config --add channels https://mirrors.bfsu.edu.cn/anaconda/pkgs/r/
目前国内提供conda镜像的大学
清华大学: https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/
北京外国语大学: https://mirrors.bfsu.edu.cn/help/anaconda/
南京邮电大学: https://mirrors.njupt.edu.cn/
南京大学: http://mirrors.nju.edu.cn/
重庆邮电大学: http://mirror.cqupt.edu.cn/
上海交通大学: https://mirror.sjtu.edu.cn/
哈尔滨工业大学: http://mirrors.hit.edu.cn/#/home
(目测哈工大的镜像同步的是最勤最新的)
查看已经添加的channelsD:\program_file_worker\anaconda>conda config --get channels
--add channels 'defaults' # lowest priority
--add channels 'https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/'
--add channels 'https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/'
--add channels 'https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/bioconda/' # highest priority
已添加的channel在哪里查看
# windows 用户在C:\Users\~\下面
windows 用户无法直接创建 .condarc 文件,需要通过指令
conda config --set show_channel_urls yes
生成该文件,然后可以通过 vim/notepad++ 再修改
三: python文件运行报错:Error: Please select a valid Python interpreter
1、更改Pycharm的设置
打开settings(CTRL + ALT + S)或者【file>settings】,打开配置框,如下图:
在查询框中输入interpreter,进行查询。
四:右侧project interpreter 中选择一个,可以选择的是show all和python.exe;选择存在的python.ext或者New新下载一个;
五:Python3变量及数据结构|循环控制语句
import gc from collections import deque val = "Hello World" print(val) # 定义变量,变量的本质是对象 ''' python中批量注释,使用三个单引号或者三个双引号 ''' var1, var2, var3, var4 = 'value1', 'value2', 'value3', 'value4' # 打印变量 print(var1, var2, var3, var4) """ python3中的变量的数据类型被划分为六种: numbers: 数据类型 string: 字符串类型 list: 列表数据类型 dictionaries: 字典类型 tuple: 元祖数据类型 sets: 结合类型 """ dictData = {} tupleData = () listData = [] # dir用来查询类或者类型的所有属性: 如dir(list) print(dir(dictData)) print("type()函数打印个数据类型: ", type(var1), type(dictData), type(var2), type(var3), type(listData), type(tupleData)) print("python中各种运算符: ", "关系运算符", "逻辑运算符", "位运算符", "算术运算符", "赋值运算符") a = 20 b = -3 print("=====================================================================================") print(a + b, a - b, a * b, a / b, a % b, abs(b), float(a)) print() a = 9 b = 3 a += b print("a= ", a) print() print("比较运算符: ") a = 3 b = 5 e = None c = 7 print(a == b) print(a != b) print(a > b) print(a < b) print(a >= b) print(a <= b) print(a is b) print(a is not b) print(e is None) print() print("链式比较符: ", a < b < c) ''' python中的is函数与==的区别 “==” 只是判断两个对象的内容是否相等 is函数不仅对比内容是否相等,还比较指针是否相等 ''' a = -256 b = -256 print("a==b :", a == b) print(a is b) print("a的内存地址: ", id(a), "b的内存地址: ", id(b)) ''' python中字符串使用: 单行字符串: (1)单引号或者双引号来表示 (2)多行字符块,也叫多行字符串,使用三个双单引号来表示 ''' a = 'line1line2' b = 'line1\ line2' print("a = ", a) print("b = ", b) c = ''' line1 line2 line3 ''' print("c: ", c) line = '老高' print("python中字符串后那些常用的方法:", dir(line)) print() print("了解某个方法的使用情况,可以使用help()函数") print("字符串的islower方法: ", help(line.islower())) print("python中list的类型: ", "list(列表)", "列表中使用得最频繁的数据类型之一,它是有序集合,与字符串一样,都属于‘系列’类型") tt = 'hello' listData = [11, 55, 66, tt, {}, [], "world", ()] print("列表: ", listData) listData.append("老公公") print("添加元素: ", listData) listLine = ['', '33', "天蓬元帅"] listData.extend(listLine) print("listData列表的内容: ", listData) print("listData列表中第三个元素是: ", listData.pop(2)) listData.reverse() print("listData数量列表中逆序操作: ", listData) listData.insert(4, "老杨") print("listData列表中插入某个值操作: ", listData) print("listData的数据类型为: ", type(listData)) print( "================================================================================================================") # 堆栈,后进先出 stack = [] stack.append(1) stack.append(2) stack.append("hello") print("取第一个元素: ", stack.pop()) print("取第二个元素: ", stack.pop()) print("取第三个元素: ", stack.pop()) # 高效的队列模拟堆栈 queueandstack = deque() queueandstack.append(22) queueandstack.append(33) queueandstack.append(44) queueandstack.append("hello") print("高效队列模拟堆栈:", list(queueandstack)) print("模拟队列,元素先进先出操作(队列): ", queueandstack.popleft()) print("模拟堆栈,元素先进后出操作(堆栈): ", queueandstack.pop()) print() print( "================================================================================================================") # 定义一个空的元组 tuple1 = () # 定义一个包含一个元素的元组,此时必须要在末位加逗号 tuple2 = (1,) print("tuple2: ", tuple2) print("获取元组第一个元素: ", tuple2[0], "tuple2元组的数据结构: ", tuple2) # 定义列表空元素 listData = [] print("listData的类型是: ", type(listData)) # 定义 包含一个元素的列表,可以在尾部添加逗号,可可以不添加 listData = [11, ] listData.append("Hello World") listData.extend("你好,欢迎来到python脚本世界!") print("列表的内容为: ", listData, "; 元素个数为: ", len(listData)) tt = "hello" t1 = (1, 2, 3, 4, 5, 6, "yes", [1, 2], (22, 33)) print("元组t1为: ", t1) t1[7][0] = 9999999 print("t1元组元素: ", t1) # 修改元组的第八个数据 # t1[8] = 9999999 print(t1) print( "================================================================================================================") print("sets集合探究: ") ''' set集合是无序与不重复元素的集合类型,定义set集合使用大括号 ''' mySet = {'hello', "hello", "Python", 'tensorflow', 2, 1, 33} print("set集合: ", mySet, "集合set的元素个数: ", len(mySet), "set随机获取集合中的元素: ", mySet.pop()) print("set集合转换为列表: ", list(mySet).pop()) ''' set的运算符与数学中的集合运算符相似,支持差,并,交等操作 另外,还有一个in的语法,用来测试某个元素是否在某个集合里面,返回一个布尔的结果 ''' helloSet = set("hello") # 通过set函数,将字符串"hello"转换为集合 tensorflowSet = set("tensorflow") # 通过set函数,将字符串"tensorflow"转换为set集合 print("判断字母'w'是否在集合tensorflowSet中: ", 'w' in tensorflowSet) print('判断字母是否在tensorflowSet集合中,并打印集合:', 'w' in tensorflowSet, ' ; ', tensorflowSet) print("===========================================================================================================") ''' 差集helloSet中有,tensorflowSet中没有的 ''' print("求集合helloSet与tensorflowSet集合的差集: ", helloSet - tensorflowSet) ''' 并集helloSet集合与tensorflowSet集合,包括两个集合都有 ''' print("helloSet集合|tensorflowSet集合求并集: ", helloSet | tensorflowSet) ''' 交集 helloSet集合与tensorflowSet集合都有的交集 ''' print("求交集:helloSet&tensorflowSet(交集): ", helloSet & tensorflowSet) ''' 对称差集: 该集合的元素不会同时出现在helloSet和tensorflowSet集合中, 结果为: 要么在helloSet集合中,要么在tensorflowSet集合中,不会同时出现在两个集合中的元素 ''' print("集合helloSet与tensorflowSet对称差集: ", helloSet ^ tensorflowSet) ''' Python中还有一个不可变集合(frozenset),它类似于元组与列表的关系 在取值上,不可变集合与集合是一样的。不同的是,frozenset里的值不能改变,也就是不能修改 ''' myTuple = ('hello', 'hello', 'Python', 2, 1, 1.8) mySet = frozenset(myTuple) # 使用frozenset函数将myTuple元组转换为不可变集合 print("不可变集合(mySet): ", mySet) ''' list(列表)删除操作: ''' print("将要删除的列表: ", listData) del listData[3:20] print("删除后的列表: ", listData) del listData[2] # 回收内存地址 gc.collect() print("再次删除后的列表: ", listData) listData.append("Linux") listData.append("centos7") listData.append("window10") listData.append("unix") listData.append(11) listData.append(22) listData.append(33) listData.append(44) listData.append("||=====||====||") listData.append(55) listData.append(66) listData.append(77) listData.append(88) print("添加元素后的列表: ", listData) del listData[10] print("删除后的列表数: ", listData, " 列表内存地址: ", id(listData)) print() print( "================================================================================================================") # 定义多元数组 mat = [ [1, 2, 3, 4], [5, 6, 7, 8], [8, 10, 11, 12], [13, 14, 15, 16] ] print() print("定义多元数组: ", mat) listChangeSet = set(listData) print("转换后的set集合: ", listChangeSet) ''' 列表转换为字典:dict()函数 列表里的元素嵌套元组 ''' myList = [('hello', 1), ('good', 2), ('ok', 3), ('linux', 4)] # 使用dict()函数将列表转换为字典 d = dict(myList) d2 = {'hello': 1, 'good': 2, 'ok': 3} # 使用大括号括起来创建字典 print('第一个字典: ', d, '; 第二个字典: ', d2) ''' 字典类型的对象通过关键字(key)来取值,它的用法是在后面的加个中括号,里面输入key的字符串 ''' print("d2字典中的(key=hello)的值: ", d2['hello'], " 完整的字典: ", d2) # 给字典添加元素 d2['system1'] = 'Linux' d2['system2'] = 'ubunto' d2['system3'] = 'Centos8' d2['system4'] = 'Window11' print(" 添加元素后的字典列表: ", d2) print("===============================================================================================================") print("keys所有的键集合: ", d2.keys()) print("values所有的键集合: ", d2.values()) print("字典所有keys转换为列表: ", list(d2.keys())) print("字典的所有的values转换的列表: ", list(d2.keys())) for item in list(d2.keys()): print("字典的值分别为: ", item)
六:变量及各种语句流程控制测试结果
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar.py
Hello World
value1 value2 value3 value4
['__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__ior__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__ror__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
type()函数打印个数据类型: <class 'str'> <class 'dict'> <class 'str'> <class 'str'> <class 'list'> <class 'tuple'>
python中各种运算符: 关系运算符 逻辑运算符 位运算符 算术运算符 赋值运算符
=====================================================================================
17 23 -60 -6.666666666666667 -1 3 20.0a= 12
比较运算符:
False
True
False
True
False
True
False
True
True链式比较符: True
a==b : True
True
a的内存地址: 1602705344944 b的内存地址: 1602705344944
a = line1line2
b = line1 line2
c:
line1
line2
line3python中字符串后那些常用的方法: ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
了解某个方法的使用情况,可以使用help()函数
python中list的类型: list(列表) 列表中使用得最频繁的数据类型之一,它是有序集合,与字符串一样,都属于‘系列’类型
列表: [11, 55, 66, 'hello', {}, [], 'world', ()]
添加元素: [11, 55, 66, 'hello', {}, [], 'world', (), '老公公']
listData列表的内容: [11, 55, 66, 'hello', {}, [], 'world', (), '老公公', '', '33', '天蓬元帅']
listData列表中第三个元素是: 66
listData数量列表中逆序操作: ['天蓬元帅', '33', '', '老公公', (), 'world', [], {}, 'hello', 55, 11]
listData列表中插入某个值操作: ['天蓬元帅', '33', '', '老公公', '老杨', (), 'world', [], {}, 'hello', 55, 11]
listData的数据类型为: <class 'list'>
================================================================================================================
取第一个元素: hello
取第二个元素: 2
取第三个元素: 1
高效队列模拟堆栈: [22, 33, 44, 'hello']
模拟队列,元素先进先出操作(队列): 22
模拟堆栈,元素先进后出操作(堆栈): hello================================================================================================================
tuple2: (1,)
获取元组第一个元素: 1 tuple2元组的数据结构: (1,)
listData的类型是: <class 'list'>
列表的内容为: [11, 'Hello World', '你', '好', ',', '欢', '迎', '来', '到', 'p', 'y', 't', 'h', 'o', 'n', '脚', '本', '世', '界', '!'] ; 元素个数为: 20
元组t1为: (1, 2, 3, 4, 5, 6, 'yes', [1, 2], (22, 33))
t1元组元素: (1, 2, 3, 4, 5, 6, 'yes', [9999999, 2], (22, 33))
(1, 2, 3, 4, 5, 6, 'yes', [9999999, 2], (22, 33))
================================================================================================================
sets集合探究:
set集合: {2, 33, 'hello', 'Python', 'tensorflow'} 集合set的元素个数: 6 set随机获取集合中的元素: 1
set集合转换为列表: tensorflow
判断字母'w'是否在集合tensorflowSet中: True
判断字母是否在tensorflowSet集合中,并打印集合: True ; {'s', 't', 'o', 'f', 'w', 'e', 'r', 'l', 'n'}
===========================================================================================================
求集合helloSet与tensorflowSet集合的差集: {'h'}
helloSet集合|tensorflowSet集合求并集: {'s', 't', 'o', 'f', 'w', 'e', 'h', 'r', 'l', 'n'}
求交集:helloSet&tensorflowSet(交集): {'l', 'o', 'e'}
集合helloSet与tensorflowSet对称差集: {'s', 't', 'f', 'w', 'h', 'r', 'n'}
不可变集合(mySet): frozenset({1, 2, 1.8, 'hello', 'Python'})
将要删除的列表: [11, 'Hello World', '你', '好', ',', '欢', '迎', '来', '到', 'p', 'y', 't', 'h', 'o', 'n', '脚', '本', '世', '界', '!']
删除后的列表: [11, 'Hello World', '你']
再次删除后的列表: [11, 'Hello World']
添加元素后的列表: [11, 'Hello World', 'Linux', 'centos7', 'window10', 'unix', 11, 22, 33, 44, '||=====||====||', 55, 66, 77, 88]
删除后的列表数: [11, 'Hello World', 'Linux', 'centos7', 'window10', 'unix', 11, 22, 33, 44, 55, 66, 77, 88] 列表内存地址: 1602705495296================================================================================================================
定义多元数组: [[1, 2, 3, 4], [5, 6, 7, 8], [8, 10, 11, 12], [13, 14, 15, 16]]
转换后的set集合: {'window10', 33, 66, 'centos7', 11, 'Hello World', 44, 77, 55, 'unix', 22, 88, 'Linux'}
第一个字典: {'hello': 1, 'good': 2, 'ok': 3, 'linux': 4} ; 第二个字典: {'hello': 1, 'good': 2, 'ok': 3}
d2字典中的(key=hello)的值: 1 完整的字典: {'hello': 1, 'good': 2, 'ok': 3}
添加元素后的字典列表: {'hello': 1, 'good': 2, 'ok': 3, 'system1': 'Linux', 'system2': 'ubunto', 'system3': 'Centos8', 'system4': 'Window11'}
===============================================================================================================
keys所有的键集合: dict_keys(['hello', 'good', 'ok', 'system1', 'system2', 'system3', 'system4'])
values所有的键集合: dict_values([1, 2, 3, 'Linux', 'ubunto', 'Centos8', 'Window11'])
字典所有keys转换为列表: ['hello', 'good', 'ok', 'system1', 'system2', 'system3', 'system4']
字典的所有的values转换的列表: ['hello', 'good', 'ok', 'system1', 'system2', 'system3', 'system4']
字典的值分别为: hello
字典的值分别为: good
字典的值分别为: ok
字典的值分别为: system1
字典的值分别为: system2
字典的值分别为: system3
字典的值分别为: system4Process finished with exit code 0
七: Python3中流程控制
import gc from collections import deque ''' (1)控制流: if 表达式1: 执行体1 elif 表达式2: 执行体2 else: 默认执行体 (2)while 条件表达式: 循环体 (3)for item in 系列数据 循环体 (4)循环控制 break continue pass ''' a = 2 b = 5 if a > b: c = a else: c = b print("C当前值为: ", c) print() getStr = input("请输入性别: ") anStr = ['先生', '女士']['female' == getStr.strip()] print('尊敬的', anStr, '你好,欢迎来到python世界.......') print() ''' while 添加表达式: 循环体 ''' c = 4 while c > 0: print("while循环当前值为: ", c) c -= 1 print() # 十进制转换为二进制 a = input("请输入一个十进制的数: ") # 把a转换为整数 d = int(a) s = "" while d != 0: d, f = divmod(d, 2) s = str(f) + s print(s) ''' for的语句形式: for item in 序列数据: statement1 ''' words = ['I', 'Love', 'Python'] for item in words[:]: words.insert(0, item) print("item: ", item) print("words列表: ", words) ''' for循环与内置函数range配置使用 ''' print("0~5的范围值,包括头不包括未: ", range(5)) print("range()函数范围值转换为列表: ", list(range(5))) print("range,打印结果为[]列表,因为range函数找不到大于零的系列: ", list(range(-5))) print("range,打印结果为开始值为-5,结束值为-1:列表内容为: ", list(range(-5, 0))) print("=========================================================================================================") ''' range三个参数,第一个为开始值,第二个参数为结束值,第三个参数为步长: (begin,end,step) ''' print("range三个参数,第三个参数为步长: ", list(range(2, 20, 2))) for item in range(10): print("item数据项: ", item) ''' 冒泡排序 ''' n = [2, 3, 6, 4, -30, 20, 22, 33, 50] print("冒泡排序前的数组为: ", n) for i in range(len(n) - 1): for j in range(len(n) - i - 1): if n[j] > n[j + 1]: n[j], n[j + 1] = n[j + 1], n[j] print("冒泡排序后的数组为: ", n)
八: 流程控制测试
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\controlFlow.py
C当前值为: 5请输入性别: female
尊敬的 女士 你好,欢迎来到python世界.......while循环当前值为: 4
while循环当前值为: 3
while循环当前值为: 2
while循环当前值为: 1请输入一个十进制的数: 6
110
item: I
item: Love
item: Python
words列表: ['Python', 'Love', 'I', 'I', 'Love', 'Python']
0~5的范围值,包括头不包括未: range(0, 5)
range()函数范围值转换为列表: [0, 1, 2, 3, 4]
range,打印结果为[]列表,因为range函数找不到大于零的系列: []
range,打印结果为开始值为-5,结束值为-1:列表内容为: [-5, -4, -3, -2, -1]
=========================================================================================================
range三个参数,第三个参数为步长: [2, 4, 6, 8, 10, 12, 14, 16, 18]
item数据项: 0
item数据项: 1
item数据项: 2
item数据项: 3
item数据项: 4
item数据项: 5
item数据项: 6
item数据项: 7
item数据项: 8
item数据项: 9
冒泡排序前的数组为: [2, 3, 6, 4, -30, 20, 22, 33, 50]
排序后的数组为: [-30, 2, 3, 4, 6, 20, 22, 33, 50]Process finished with exit code 0
九: Python3高级篇:进程与线程
低维认知是方法论 高维认知是能量场 多进程|多线程认知: 1.1 进程(progress) (1)进程是计算机中进行资源分配和调度的一个独立单位,是运行应用程序的基本单元 (2)进程是线程的载体,一个进程可以包含一个或者多个线程 (3)进程是计算机中“已经运行程序”的载体 (4)进程间相互独立,互不影响,进程是程序指令和数据真正运行实例,在多进程中,同一个变量资源,各自有一份备份存在于每一个进程中,这些共享资源相互独立,互不影响 (5)每一个经常都有自己独立的地址空间,内存,数据栈及其运行状态的辅助数据 1.2 线程(thread) (1)线程是进程执行程序的路线 (2)线程是进程的一个实体,是CPU调度和分派的基本单元 (3)线程是操作系统能够进行运算调度的最小单元 (4)一个进程内的多个线程之间可以通过共享资源进行通信,但如果不对共享资源进行安全控制,有可能多个线程同时修改共享资源而导致 共享资源混乱
9.1 进程实战一:使用Process类创建进程
# -*- coding:utf-8 -*- import os from multiprocessing import Process import time ''' 低维认知是方法论 高维认知是能量场 多进程|多线程认知: 1.1 进程(progress) (1)进程是计算机中进行资源分配和调度的一个独立单位,是运行应用程序的基本单元 (2)进程是线程的载体,一个进程可以包含一个或者多个线程 (3)进程是计算机中“已经运行程序”的载体 (4)进程间相互独立,互不影响,进程是程序指令和数据真正运行实例,在多进程中,同一个变量资源,各自有一份备份存在于每一个进程中,这些共享资源相互独立,互不影响 (5)每一个经常都有自己独立的地址空间,内存,数据栈及其运行状态的辅助数据 1.2 线程(thread) (1)线程是进程执行程序的路线 (2)线程是进程的一个实体,是CPU调度和分派的基本单元 (3)线程是操作系统能够进行运算调度的最小单元 (4)一个进程内的多个线程之间可以通过共享资源进行通信,但如果不对共享资源进行安全控制,有可能多个线程同时修改共享资源而导致 共享资源混乱 ''' ''' 实例一: 使用multiprocessing模块的Process类来创建进程 ''' # 定义进程处理器 def processHandler(interval): print("开始执行子进程处理器") print("只是子进程pid: (%s), 父进程PpId: (%s)" % (os.getpid(), os.getppid())) print("子进程处理器执行完毕") # 执行主程序 def subProcessHandlerOne(interval): print("子进程(%s)开始执行,父进程为(%s)" % (os.getpid(), os.getppid())) t_start = time.time() # 单位毫秒 # 程序将被挂起interval秒 time.sleep(interval) t_end = time.time() print("子进程处理器(%s)执行时间:'%0.2f'秒" % (os.getpid(), t_end - t_start)) def subProcessHandlerTwo(interval): print("子进程(%s)开始执行,父进程为(%s)" % (os.getpid(), os.getppid())) t_start = time.time() # 单位毫秒 # 程序将被挂起interval秒 time.sleep(interval) t_end = time.time() print("子进程处理器(%s)执行时间:'%0.2f'秒" % (os.getpid(), t_end - t_start)) def main(): print("===============================================================================") print("主进程开始.............") print("主进程PID: (%s)............." % os.getpid()) p = Process(target=processHandler, name="First-Process", args=(1,)) # 实例化Process进程类 p2 = Process(target=subProcessHandlerOne, args=(2,)) p3 = Process(target=subProcessHandlerTwo, args=(3,), name="Sub-progress") # 启动子进程 p.start() p2.start() p3.start() # 告诉主进程阻塞,等待子进程执行完毕后再运行 p.join() print("主进程继续往下执行..........") print("==================================P2,P3进程信息========================================") # 如果p2,p3进程还在执行,就会返回True print("p2,is_alive=%s" % p2.is_alive()) print("p3,is_alive=%s" % p3.is_alive()) # 输出p2与p3的别名和PID print("p2.name=%s" % p2.name) print("p2.pid=%s" % p2.pid) print("p3.name=%s" % p3.name) print("p3.pid=%s" % p3.pid) print("=================================等待子进程执行完毕===============================") p2.join() p3.join() print("所有的子进程执行完毕后,主进程再接着执行至结束.....................") if __name__ == '__main__': main()
运行实例效果:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar\MultProcessAndMultThreadGrammar.py
===============================================================================
主进程开始.............
主进程PID: (11704).............
开始执行子进程处理器
只是子进程pid: (10656), 父进程PpId: (11704)
子进程处理器执行完毕
子进程(18284)开始执行,父进程为(11704)
主进程继续往下执行..........
===============================================================================
p2,is_alive=True
p3,is_alive=True
p2.name=Process-2
p2.pid=18284
p3.name=Sub-progress
p3.name=17120
=================================等待子进程执行完毕===============================
子进程(17120)开始执行,父进程为(11704)
子进程处理器(18284)执行时间:'2.00'秒
子进程处理器(17120)执行时间:'3.00'秒
所有的子进程执行完毕后,主进程再接着执行至结束.....................
9.2进程实战二:使用Process类的子类创建进程
# -*- coding:utf-8 -*- import os from multiprocessing import Process import time ''' 实例二: 使用multiprocessing模块的Process类的子类来创建进程 ''' # 继承Process类来创建进程 class SubProcess(Process): # 由于Process类本身也有__init__初始化方法,这个方法相当于重写了父类的这个方法 def __init__(self, interval, name='', target=None, args=()): Process.__init__(self) # 调用父类的初始化方法 self.interval = interval # 接受参数interval if name: self.name = name # 如果传递了name,则为子进程创建name属性,否则使用默认的name属性 # 重写Process类的run方法 def run(self): print("子进程(%s) 开始执行, 父进程为 (%s) " % (os.getpid(), os.getppid())) t_start = time.time() time.sleep(self.interval) t_stop = time.time() print("子进程(%s)执行结束,耗时%0.2f 秒" % (os.getpid(), t_stop - t_start)) # 在SubProcess类中定义的一个普通的方法 def processHandler(self, interval): print("processHandler普通方法执行开始======================begin======================================") print("processHandler子进程(%s) 开始执行, 父进程为 (%s) " % (os.getpid(), os.getppid())) t_start = time.time() time.sleep(self.interval) t_stop = time.time() print("processHandler子进程(%s)执行结束,耗时%0.2f 秒" % (os.getpid(), t_stop - t_start)) print("processHandler普通方法执行结束=======================end=====================================") if __name__ == "__main__": print("-------------------父进程开始执行------------------------------") # 输出当前程序的PID print("父进程PID:%s " % os.getpid()) p1 = SubProcess(interval=1, name="Sub-process-one") p2 = SubProcess(interval=2) p3 = SubProcess(interval=2, name="Sub-progress-three") # 对应一个不包括target属性的Process类执行start()方法后,就会执行这个类中run()方法 p1.start() p2.start() print("直接调用p3子进程的普通方法processHandler============开始") # 直接调用SubProcess中的普通方法 p3.processHandler(interval=3) print("直接调用p3子进程的普通方法processHandler============结束") print("==================================P2,P3进程信息========================================") # 输出p1,p2的运行状态,就会返回True # 输出p2与p3的别名和PID print("p1.name=%s" % p1.name) print("p1.pid=%s" % p1.pid) print("p2.name=%s" % p2.name) print("p2.pid=%s" % p2.pid) print("p3.name=%s" % p3.name) print("p3.pid=%s" % p3.pid) print("=================================等待子进程执行完毕===============================") p1.join() p2.join() print("所有的子进程执行完毕后,主进程再接着执行至结束.....................")
实例运行结果:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar\MultProcessBySubClassCreateProcess.py
-------------------父进程开始执行------------------------------
父进程PID:9756
直接调用p3子进程的普通方法processHandler============开始
processHandler普通方法执行开始======================begin======================================
processHandler子进程(9756) 开始执行, 父进程为 (18300)
子进程(12544) 开始执行, 父进程为 (9756)
子进程(16416) 开始执行, 父进程为 (9756)
子进程(12544)执行结束,耗时1.00 秒
processHandler子进程(9756)执行结束,耗时2.00 秒
processHandler普通方法执行结束=======================end=====================================
直接调用p3子进程的普通方法processHandler============结束
==================================P2,P3进程信息========================================
p1.name=Sub-process-one
p1.pid=12544
p2.name=SubProcess-2
p2.pid=16416
p3.name=Sub-progress-three
p3.pid=None
=================================等待子进程执行完毕===============================
子进程(16416)执行结束,耗时2.00 秒
所有的子进程执行完毕后,主进程再接着执行至结束.....................Process finished with exit code 0
9.3 进程池技术(Pool)
# -*- coding:utf-8 -*- import os from multiprocessing import Pool import time ''' 实例三: 使用multiprocessing模块的Pool进程池类的子类来创建进程 ''' def task(task_name): print("子进程(%s) 开始执行, 父进程为 (%s) , 执行的任务: %s" % (os.getpid(), os.getppid(), task_name)) # 休眠1秒 time.sleep(1) if __name__ == "__main__": # 输出当前程序的PID print("父进程PID:%s " % os.getpid()) p = Pool(5) for i in range(100): # 使用非阻塞的方式调用task函数 p.apply_async(task, args=("TaskProcess--%s" % i,)) print("等待所有的子任务完成.................") # 关闭进程池,关闭后p不在接收新的任务 p.close() # 等待子进程执行完毕 p.join() print("所有子进程结束.....................")
运行结果:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar\MultProcessByPoolCreateProcess.py
父进程PID:18420
等待所有的子任务完成.................
子进程(18020) 开始执行, 父进程为 (18420) , 执行的任务: TaskProcess--0
子进程(13376) 开始执行, 父进程为 (18420) , 执行的任务: TaskProcess--1
子进程(17752) 开始执行, 父进程为 (18420) , 执行的任务: TaskProcess--2
子进程(6072) 开始执行, 父进程为 (18420) , 执行的任务: TaskProcess--3
子进程(6256) 开始执行, 父进程为 (18420) , 执行的任务: TaskProcess--4
子进程(18020) 开始执行, 父进程为 (18420) , 执行的任务: TaskProcess--5
子进程(13376) 开始执行, 父进程为 (18420) , 执行的任务: TaskProcess--6
子进程(17752) 开始执行, 父进程为 (18420) , 执行的任务: TaskProcess--7
子进程(6072) 开始执行, 父进程为 (18420) , 执行的任务: TaskProcess--8
子进程(6256) 开始执行, 父进程为 (18420) , 执行的任务: TaskProcess--9
所有子进程结束.....................
十: 多进程之间相互独立
多进程中的各进程相互独立,互不影响, 因此在多进程中的共享资源不同被给进进程任务修改导致共享资源混乱的问题;如下定义一个全局共享资源g_name演示共享资源在多进程中的独立性,因为每一个进程都具有一个共享资源的副本, 在本进程内的修改并不会影响全局共享资源;
# -*- coding:utf-8 -*- import os from multiprocessing import Process, Queue import time ''' 实例三: 使用multiprocessing模块的Queue来完成进程间的通信 ''' def plus(): print("----------------------1-子进程(%s)开始工作--------------------------" % os.getpid()) global g_num g_num += 50 print("g_name is %d" % g_num) print("----------------------1-子进程(%s)结束工作--------------------------" % os.getpid()) def minus(): print("----------------------2-子进程(%s)开始工作--------------------------" % os.getpid()) global g_num g_num -= 50 print("g_name is %d" % g_num) print("----------------------2-子进程(%s)结束工作--------------------------" % os.getpid()) # 定义一个变量 g_num = 100 if __name__ == "__main__": # 输出当前程序的PID print("父进程PID:%s " % os.getpid()) print('全局资源[g_name] is %d' % g_num) p1 = Process(target=plus) p2 = Process(target=minus) # 使用非阻塞的方式调用task函数 p1.start() p2.start() print("等待所有的子任务完成.................") # 关闭进程池,关闭后p不在接收新的任务 p1.join() # 等待子进程执行完毕 p2.join() print("所有子进程结束.....................")
多次运行都是同样的结果, plus()修改共享资源g_num并不会影响minus()修改g_name全局资源;
运行结果:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar\MultProcessToProcessCommunication.py
父进程PID:10452
全局资源[g_name] is 100
等待所有的子任务完成.................
----------------------1-子进程(4496)开始工作--------------------------
g_name is 150
----------------------1-子进程(4496)结束工作--------------------------
----------------------2-子进程(13596)开始工作--------------------------
g_name is 50
----------------------2-子进程(13596)结束工作--------------------------
所有子进程结束.....................Process finished with exit code 0
多次运行都是这样结果
十一: 多进程之间队列使用
怎样在跨进程之间进行通信:使用数据结构队列来实现共享资源在多进程之间进行通信
# -*- coding:utf-8 -*- from multiprocessing import Queue''' 实例四: multiprocessing模块的Queue来在多进程中的使用 ''' if __name__ == "__main__": q = Queue(3) # 初始化一queue对象,最多可以接收三条put消息 q.put("消息1") q.put("消息2") print("队列是否已经满: %s" % q.full()) q.put("消息3") print("队列是否已经满: %s" % q.full()) # 因为队列已经满,下面的try会抛出异常 try: # 2秒后,队列还是满的,就会抛出异常 q.put("消息4", True, 2) except Exception as err: print("1消息队列已经满了,消息的消息数量为: %d " % q.qsize(), " 系统异常: %s" % err) try: # 会立刻抛出异常,队列满时,再放消息立刻抛出异常 q.put_nowait("消息4") except Exception as err: print("2消息队列已经满了,消息的消息数量为: %d " % q.qsize(), " 系统异常: %s" % err) # 读取消息时,先判断消息队列是否为空,在读取 if not q.empty(): print("从消息队列中读取消息") for i in range(q.qsize()): print("从队列中取出的消息为: %s" % q.get_nowait()) # 判断消息队列是否已经满,在写入消息 if not q.full(): # q.put_nowait("消息4") # 没有下面这条语句,消息不会存入队列,待查询........ q.put("消息4", True, 1) print("从消息队列中读取消息的数量为%d" % q.qsize()) # 再次读取队列中的消息 if not q.empty(): print("从消息队列中读取消息的数量为%d" % q.qsize()) for i in range(q.qsize()): print("从队列中取出的消息为: %s" % q.get_nowait())
运行效果如下:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar\MultProcessToProcessCommunicationQueue.py
队列是否已经满: False
队列是否已经满: True
1消息队列已经满了,消息的消息数量为: 3 系统异常:
2消息队列已经满了,消息的消息数量为: 3 系统异常:
从消息队列中读取消息
从队列中取出的消息为: 消息1
从队列中取出的消息为: 消息2
从队列中取出的消息为: 消息3
从消息队列中读取消息的数量为1
从消息队列中读取消息的数量为1
从队列中取出的消息为: 消息4
十二: 多进程之间使用队列通信
# -*- coding:utf-8 -*- from multiprocessing import Process, Queue import time ''' 实例五: 使用multiprocessing模块的Queue来完成进程间的通信 Python底层封装了Queue(队列)和Pipes(管道)等多种方式来交换数据。进程之间有时需要通信,操作系统提供了很多机制来实现进程间的通信 可以使用multiprocessing模块的queue队列来实现进程之间的通信; ''' # 想队列中写入数据 def write_task(queue_object): if not queue_object.full(): for i in range(10): message = "消息" + str(i) queue_object.put(message) print("写入消息:%s" % message) # 从队列中读取数据 def read_task(queue_object): # 休眠一秒 time.sleep(1) while not queue_object.empty(): # 等待2秒,如果还没有读取到任何消息,则抛出Queue.Empty异常 print("读取:%s" % queue_object.get(True, 2)) if __name__ == "__main__": print("-------------父进程开始------------------------------") q = Queue() pw = Process(target=write_task, args=(q,)) pr = Process(target=read_task, args=(q,)) pw.start() pr.start() pw.join() pr.join() print("---------------父进程结束------------------------------")
生产消息进程与消费消息进程通信测试结果:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar\MultProcessToProcessCommunicationQueue.py
-------------父进程开始------------------------------
写入消息:消息0
写入消息:消息1
写入消息:消息2
写入消息:消息3
写入消息:消息4
写入消息:消息5
写入消息:消息6
写入消息:消息7
写入消息:消息8
写入消息:消息9
读取:消息0
读取:消息1
读取:消息2
读取:消息3
读取:消息4
读取:消息5
读取:消息6
读取:消息7
读取:消息8
读取:消息9
---------------父进程结束------------------------------Process finished with exit code 0
十三: Python3中线程
线程认知:
(1)线程是进程实际运行的路线
(2)线程是操作系统能够进行运算调度的最小单元
(3)一个引用可以包含多个进程,一个进程可以包含多个线程
(4)线程是操作系统直接支持的执行单元
使用Thread([group[,target[,name[,args[,kwargs]]]]])
参数说明:
group:值为None,为以后版本保留。
target:表示一个可调用的名称,线程启动时,run()方法将调用此对象,默认值为None,表示不调用任何内容
name: 表示当前线程的名称,默认创建一个"Thread-N"格式的唯一名称
args: 表示传递给target函数的参数元组
kwargs:表示传递给target的参数字典
线程认知升维
# -*- coding:utf-8 -*- import threading, time ''' 线程认知: (1)线程是进程实际运行的路线 (2)线程是操作系统能够进行运算调度的最小单元 (3)一个引用可以包含多个进程,一个进程可以包含多个线程 (4)线程是操作系统直接支持的执行单元 使用Thread([group[,target[,name[,args[,kwargs]]]]]) 参数说明: group:值为None,为以后版本保留。 target:表示一个可调用的名称,线程启动时,run()方法将调用此对象,默认值为None,表示不调用任何内容 name: 表示当前线程的名称,默认创建一个"Thread-N"格式的唯一名称 args: 表示传递给target函数的参数元组 kwargs:表示传递给target的参数字典 ''' def thread_handler(): for item in range(3): # 休眠1秒 time.sleep(1) print("thread name is %s" % threading.current_thread().name) if __name__ == "__main__": print("-----------主线程开始---------------------") # 创建4个线程,放入列表 threads = [threading.Thread(target=thread_handler) for i in range(4)] for itemThread in threads: # 开启线程 itemThread.start() for itemThread in threads: # 告诉主线程,等待子线程运行结束,在接着运行 itemThread.join() print("-------------主线程结束--------------------")
测试运行结果:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar\MultiThreadByThreadingCreate.py
-----------主线程开始---------------------
thread name is Thread-1 (thread_handler)
thread name is Thread-2 (thread_handler)thread name is Thread-3 (thread_handler)thread name is Thread-4 (thread_handler)
thread name is Thread-1 (thread_handler)
thread name is Thread-2 (thread_handler)thread name is Thread-3 (thread_handler)thread name is Thread-4 (thread_handler)
thread name is Thread-1 (thread_handler)
thread name is Thread-3 (thread_handler)
thread name is Thread-2 (thread_handler)
thread name is Thread-4 (thread_handler)
-------------主线程结束--------------------Process finished with exit code 0
十四: 多线程之间可以共享资源
我们知道,多个进程之间相互独立,有自己的内存地址空间,独立的内存,独立的共享资源副本,独立的数据栈....它们并不能共享资源,也即是每个进程对自己本地内存中共享资源修改,并不会影响到主内存中的同名共享资源,因此某个进程不会因修改本地内存中的资源影响到其它 进程中同名的资源,不会带来共享资源混乱的问题;
但是,多线程之间同时修改共享资源,可能会导致共享资源混乱问题;下面我们来元素多线程同时操作共享变量g_name, 看看是否可以通过共享资源进行多线程之间的通信协作;
实例一:公共资源可在多线程间共享 # -*- coding:utf-8 -*- from threading import Thread import time ''' 多线程之间通过共享资源进行通信 ''' def plus(): print("---------------子线程1开始------------------") global g_name g_name += 50 print("全局共享g_name资源 is %d" % g_name) print("----------------子进程1结束-----------------") def minus(): print("---------------子线程2开始------------------") global g_name g_name -= 50 print("全局共享g_name资源 is %d" % g_name) print("----------------子进程2结束-----------------") g_name = 100 if __name__ == '__main__': print('-----------------主进程开始---------------------') print("全局变量g_name is %d" % g_name) t1 = Thread(target=plus) t2 = Thread(target=minus) t1.start() t2.start() t1.join() t2.join() print("------------------主进程结束---------------------")
测试运行结果:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar\MultiThreadByThreadingShareParam.py
-----------------主进程开始---------------------
全局变量g_name is 100
---------------子线程1开始------------------
全局共享g_name资源 is 150
----------------子进程1结束-----------------
---------------子线程2开始------------------
全局共享g_name资源 is 100
----------------子进程2结束-----------------
------------------主进程结束---------------------Process finished with exit code 0
实例二: 共享资源未作安全控制,导致多线程修改公共资源,混乱,线程序号没与对应计算器值对应的情况
# -*- coding:utf-8 -*- import threading import time ''' 多线程操作共享资源: 共享变量count(公共计数器),来演示多线程同时修改共享资源带来数据混乱问题 我们知道,多线程的优势在于并发性,可以同时运行多个任务;但是多线程操作共享数据时,可能带来数据不同步的问题,下面我们通过该例来演示 多线程修改公共计数器导致不同步问题,并进行解决 ''' # 公共计数器,初始化值为1 count = 1 # 定义线程处理函数 def handlerCount(arg): global count # 工具计数器,计算器count的平方 count *= 2 time.sleep(arg % 2) print("Thread-%s , " % arg, " count(计数器): %s" % count) if __name__ == "__main__": print("-------------------主线程开始----------------") threads = [] for i in range(1, 11): # 联系的序号作为线程处理器的参数 t = threading.Thread(target=handlerCount, args=(i,)) t.start() # 创建的线程加入到列表中去 threads.append(t) for t in threads: # 循环线程列表,告诉主线程等待对应的子线程执行完成后,在接着运行主线程余下的代码逻辑 t.join() print("-------------------主线程结束----------------")
多线程修改公共资源混乱运行效果:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\MultiThreadByThreadingShareParamCount.py
-------------------主线程开始----------------
Thread-2 , count(计数器): 4
Thread-4 , count(计数器): 16
Thread-6 , count(计数器): 64
Thread-8 , count(计数器): 256
Thread-10 , count(计数器): 1024
Thread-1 , count(计数器): 1024
Thread-3 , count(计数器): 1024
Thread-5 , count(计数器): 1024
Thread-7 , count(计数器): 1024
Thread-9 , count(计数器): 1024
-------------------主线程结束----------------Process finished with exit code 0
对实例一:
从运行结果可以看出,在同一个进程内的所有线程能共享全局变量g_name,t1线程运行后,全局资源的值为150,t2线程运行处理器方法后减去50后,全局变量的值变为(150-50=100)100,同一进程内的多线程之间不借助于其他方式的前提下,各线程之间可以共享全局资源;
实例二: 线程的执行序号与计数器没对应上;我们对上述程序稍加修改,加互斥锁,保证序号与计数器对应
# -*- coding:utf-8 -*- import threading import time ''' 多线程操作共享资源: 共享变量count(公共计数器),来演示多线程同时修改共享资源带来数据混乱问题 我们知道,多线程的优势在于并发性,可以同时运行多个任务;但是多线程操作共享数据时,可能带来数据不同步的问题,下面我们通过该例来演示 多线程修改公共计数器导致不同步问题,并进行解决 ''' # 公共计数器,初始化值为1 count = 1 # 锁实例化 lock = threading.RLock() # 定义线程处理函数 def handlerCount(arg): global count # 工具计数器,计算器count的平方 lock.acquire() # 加锁 count *= 2 time.sleep(arg % 2) print("Thread-%s , " % arg, " count(计数器): %s" % count) lock.release() # 释放锁 if __name__ == "__main__": print("-------------------主线程开始----------------") threads = [] for i in range(1, 11): # 联系的序号作为线程处理器的参数 t = threading.Thread(target=handlerCount, args=(i,)) t.start() # 创建的线程加入到列表中去 threads.append(t) for t in threads: # 循环线程列表,告诉主线程等待对应的子线程执行完成后,在接着运行主线程余下的代码逻辑 t.join() print("-------------------主线程结束----------------")
加锁后运行效果:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\MultiThreadByThreadingShareParamCount.py
-------------------主线程开始----------------
Thread-1 , count(计数器): 2
Thread-2 , count(计数器): 4
Thread-3 , count(计数器): 8
Thread-4 , count(计数器): 16
Thread-5 , count(计数器): 32
Thread-6 , count(计数器): 64
Thread-7 , count(计数器): 128
Thread-8 , count(计数器): 256
Thread-9 , count(计数器): 512
Thread-10 , count(计数器): 1024
-------------------主线程结束----------------Process finished with exit code 0
十五: 多线程访问共享资源带来的线程安全问题|及解决方案
由于多线程对全局共享资源可以随意修改,这可能造成多线程之间对全局变量的混乱操作,为了解决多线程资源竞争问题,通常使用互斥锁,防止多线程同时读写某一块内存区域,保证同一时刻只有一个线程修改共享资源,其它线程只能处于阻塞状态,等待持有锁资源的线程释放后,再参与锁的竞争.....
15.1:线程安全解决方案一:Lock类
# -*- coding:utf-8 -*- from threading import Thread, Lock import time n = 100 # 共100张票 ''' threading模块中的使用Lock类可以很方便的处理锁定: Lock类有2个方法: acquire()锁定与释放release()释放锁 ''' def task_lock(): global n # 加锁 mutex.acquire() temp = n time.sleep(0.1) n = temp - 1 print("购买成功,剩余%d张电影票" % n) # 释放锁 mutex.release() if __name__ == '__main__': mutex = Lock() # 创建50个线程同时抢票 threads = [] for item in range(50): subThread = Thread(target=task_lock) threads.append(subThread) # 将线程实例存入列表中 subThread.start() for t in threads: t.join() # 等待子线程运行结束,再运行子线程 print('------------------------主线程运行结束-------------------------')
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar\MultiThreadByThreadingShareResourceSecurity.py
购买成功,剩余99张电影票
购买成功,剩余98张电影票
购买成功,剩余97张电影票
购买成功,剩余96张电影票
购买成功,剩余95张电影票
购买成功,剩余94张电影票
购买成功,剩余93张电影票
购买成功,剩余92张电影票
购买成功,剩余91张电影票
购买成功,剩余90张电影票
购买成功,剩余89张电影票
购买成功,剩余88张电影票
购买成功,剩余87张电影票
购买成功,剩余86张电影票
购买成功,剩余85张电影票
购买成功,剩余84张电影票
购买成功,剩余83张电影票
购买成功,剩余82张电影票
购买成功,剩余81张电影票
购买成功,剩余80张电影票
购买成功,剩余79张电影票
购买成功,剩余78张电影票
购买成功,剩余77张电影票
购买成功,剩余76张电影票
购买成功,剩余75张电影票
购买成功,剩余74张电影票
购买成功,剩余73张电影票
购买成功,剩余72张电影票
购买成功,剩余71张电影票
购买成功,剩余70张电影票
购买成功,剩余69张电影票
购买成功,剩余68张电影票
购买成功,剩余67张电影票
购买成功,剩余66张电影票
购买成功,剩余65张电影票
购买成功,剩余64张电影票
购买成功,剩余63张电影票
购买成功,剩余62张电影票
购买成功,剩余61张电影票
购买成功,剩余60张电影票
购买成功,剩余59张电影票
购买成功,剩余58张电影票
购买成功,剩余57张电影票
购买成功,剩余56张电影票
购买成功,剩余55张电影票
购买成功,剩余54张电影票
购买成功,剩余53张电影票
购买成功,剩余52张电影票
购买成功,剩余51张电影票
购买成功,剩余50张电影票
------------------------主线程运行结束-------------------------Process finished with exit code 0
15.2:线程安全解决方案二:Semaphore信号量
# -*- coding:utf-8 -*- import threading import time import random ''' 处理线程安全问题,除了使用“锁”以外,还可以使用"信号量"来同步线程之间的顺序关系 信号量(semaphore)是一种带计数的线程同步机制。调用release()函数后,计算器会加一;调用acquire()函数后,计算器会减一; 当计数为0时,线程会自动阻塞,等待release被调用; 在实际清空中,希望多线程以一定的先后顺序来执行。例如,生产者与消费者的关系,一定是先生产后消费; ''' # 创建信号量,初始化计数为0 semaphore = threading.Semaphore(0) # 消费者函数 def consumer(): print("consumer : 挂起....") # 执行一次就减一 semaphore.acquire() print("consumer : 消费%s." % item) # 定义生产者 def producer(): global item time.sleep(3) item = random.randint(1, 1000) print("producer : 生产 %s." % item) # 函数执行一次计数器加一 semaphore.release() item = "" threads = [] for i in range(0, 2): t1 = threading.Thread(target=producer) # 生产者线程 t2 = threading.Thread(target=consumer) # 消费者线程 t1.start() t2.start() threads.append(t1) threads.append(t2) for t in threads: t.join() # 循环告知主线程等待对应子线程运行完成后,再接着运行主线程余下的部分代码
运行效果:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar\MultiThreadByThreadingShareResourceSemaphore.py
consumer : 挂起....
consumer : 挂起....
producer : 生产 664.
consumer : 消费664.
producer : 生产 258.
consumer : 消费258.Process finished with exit code 0
15.3:线程安全解决方案三:Condition条件锁
# -*- coding:utf-8 -*- from threading import Thread from threading import Condition import time import random ''' 使用添加锁来确保多线程对共享变量操作的安全保障: 条件锁: 可以使用threading模块中的Condition类。它也有acquire()方法,和release()方法,而且还有wait,notify和notifyAll() |高版本该方法过时,用这个代替: notify_all() ''' # 创建条件锁 condition = Condition() # 定义商品编号 itemNum = 0 # 定义商品的个数 item = 0 # 定义消费者 def consumer(): global item global itemNum # 锁住资源 condition.acquire() # 无产品,则让线程等待 while 0 == itemNum: print("consumer : 挂起.....") condition.wait() itemNum -= 1 print("consumer : 消费%s." % item, itemNum) condition.release() def producer(): global item global itemNum time.sleep(3) # 锁住共享资源 condition.acquire() item = random.randint(1, 1000) itemNum += 1 print("producer : 生成 %s." % item) condition.notify_all() # 释放资源 condition.release() threads = [] for i in range(0, 2): t1 = Thread(target=producer) t2 = Thread(target=consumer) t1.start() t2.start() threads.append(t1) threads.append(t2) for t in threads: t.join()
运行效果:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar\MultiThreadByThreadingShareResourceCondition.py
consumer : 挂起.....
consumer : 挂起.....
producer : 生成 515.
consumer : 消费515. 0
consumer : 挂起.....
producer : 生成 172.
consumer : 消费172. 0Process finished with exit code 0
十六: 多线程之间使用队列进行通信
# -*- coding:utf-8 -*- from queue import Queue import random, threading, time ''' 使用生产者与消费者模式(queue队列)在多线程之间进行通信 ''' # 生成者类编写 class Producer(threading.Thread): # 重写父类的init方法 def __init__(self, name, queue): # 调用父类的init方法 threading.Thread.__init__(self, name=name) self.data = queue # 队列初始化 # 重写父类的run方法 def run(self): for i in range(50): print("生成者%s将产品%d加入队列!" % (self.name, i)) self.data.put("producer-message-" + str(i)) time.sleep(random.random()) print("生成者%s完成!" % self.name) # 消费者类编写 class Consumer(threading.Thread): # 重写父类的init方法 def __init__(self, name, queue): # 调用父类的init方法 threading.Thread.__init__(self, name=name) self.data = queue # 队列初始化 # 重写父类的run方法 def run(self): for i in range(50): val = self.data.get() print("消费者%s将产品[%s]从队列中取出!" % (self.name, val)) time.sleep(random.random()) print("消费者%s完成!" % self.name) if __name__ == "__main__": print("-------------------主线程开始-------------------------") queue = Queue() producer = Producer("Producer", queue) consumer = Consumer("Consumer", queue) producer.start() consumer.start() producer.join() consumer.join() print("-------------------主线程结束-------------------------")
测试运行效果:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar\MultiThreadByThreadingCommunicationQueue.py
-------------------主线程开始-------------------------
生成者Producer将产品0加入队列!
消费者Consumer将产品[producer-message-0]从队列中取出!
生成者Producer将产品1加入队列!
消费者Consumer将产品[producer-message-1]从队列中取出!
生成者Producer将产品2加入队列!
消费者Consumer将产品[producer-message-2]从队列中取出!
生成者Producer将产品3加入队列!
消费者Consumer将产品[producer-message-3]从队列中取出!
生成者Producer将产品4加入队列!
消费者Consumer将产品[producer-message-4]从队列中取出!
生成者Producer将产品5加入队列!
消费者Consumer将产品[producer-message-5]从队列中取出!
生成者Producer将产品6加入队列!
消费者Consumer将产品[producer-message-6]从队列中取出!
生成者Producer将产品7加入队列!
消费者Consumer将产品[producer-message-7]从队列中取出!
生成者Producer将产品8加入队列!
消费者Consumer将产品[producer-message-8]从队列中取出!
生成者Producer将产品9加入队列!
生成者Producer将产品10加入队列!
消费者Consumer将产品[producer-message-9]从队列中取出!
生成者Producer将产品11加入队列!
生成者Producer将产品12加入队列!
生成者Producer将产品13加入队列!
生成者Producer将产品14加入队列!
消费者Consumer将产品[producer-message-10]从队列中取出!
生成者Producer将产品15加入队列!
消费者Consumer将产品[producer-message-11]从队列中取出!
生成者Producer将产品16加入队列!
生成者Producer将产品17加入队列!
消费者Consumer将产品[producer-message-12]从队列中取出!
生成者Producer将产品18加入队列!
生成者Producer将产品19加入队列!
消费者Consumer将产品[producer-message-13]从队列中取出!
生成者Producer将产品20加入队列!
消费者Consumer将产品[producer-message-14]从队列中取出!
消费者Consumer将产品[producer-message-15]从队列中取出!
生成者Producer将产品21加入队列!
生成者Producer将产品22加入队列!
消费者Consumer将产品[producer-message-16]从队列中取出!
生成者Producer将产品23加入队列!
消费者Consumer将产品[producer-message-17]从队列中取出!
消费者Consumer将产品[producer-message-18]从队列中取出!
生成者Producer将产品24加入队列!
消费者Consumer将产品[producer-message-19]从队列中取出!
生成者Producer将产品25加入队列!
消费者Consumer将产品[producer-message-20]从队列中取出!
消费者Consumer将产品[producer-message-21]从队列中取出!
消费者Consumer将产品[producer-message-22]从队列中取出!
生成者Producer将产品26加入队列!
生成者Producer将产品27加入队列!
消费者Consumer将产品[producer-message-23]从队列中取出!
生成者Producer将产品28加入队列!
消费者Consumer将产品[producer-message-24]从队列中取出!
消费者Consumer将产品[producer-message-25]从队列中取出!
生成者Producer将产品29加入队列!
生成者Producer将产品30加入队列!
消费者Consumer将产品[producer-message-26]从队列中取出!
生成者Producer将产品31加入队列!
消费者Consumer将产品[producer-message-27]从队列中取出!
生成者Producer将产品32加入队列!
消费者Consumer将产品[producer-message-28]从队列中取出!
生成者Producer将产品33加入队列!
消费者Consumer将产品[producer-message-29]从队列中取出!
生成者Producer将产品34加入队列!
消费者Consumer将产品[producer-message-30]从队列中取出!
生成者Producer将产品35加入队列!
消费者Consumer将产品[producer-message-31]从队列中取出!
生成者Producer将产品36加入队列!
生成者Producer将产品37加入队列!
生成者Producer将产品38加入队列!
消费者Consumer将产品[producer-message-32]从队列中取出!
生成者Producer将产品39加入队列!
生成者Producer将产品40加入队列!
消费者Consumer将产品[producer-message-33]从队列中取出!
生成者Producer将产品41加入队列!
生成者Producer将产品42加入队列!
消费者Consumer将产品[producer-message-34]从队列中取出!
生成者Producer将产品43加入队列!
消费者Consumer将产品[producer-message-35]从队列中取出!
消费者Consumer将产品[producer-message-36]从队列中取出!
生成者Producer将产品44加入队列!
消费者Consumer将产品[producer-message-37]从队列中取出!
消费者Consumer将产品[producer-message-38]从队列中取出!
消费者Consumer将产品[producer-message-39]从队列中取出!
生成者Producer将产品45加入队列!
消费者Consumer将产品[producer-message-40]从队列中取出!
生成者Producer将产品46加入队列!
生成者Producer将产品47加入队列!
生成者Producer将产品48加入队列!
消费者Consumer将产品[producer-message-41]从队列中取出!
生成者Producer将产品49加入队列!
消费者Consumer将产品[producer-message-42]从队列中取出!
消费者Consumer将产品[producer-message-43]从队列中取出!
生成者Producer完成!
消费者Consumer将产品[producer-message-44]从队列中取出!
消费者Consumer将产品[producer-message-45]从队列中取出!
消费者Consumer将产品[producer-message-46]从队列中取出!
消费者Consumer将产品[producer-message-47]从队列中取出!
消费者Consumer将产品[producer-message-48]从队列中取出!
消费者Consumer将产品[producer-message-49]从队列中取出!
消费者Consumer完成!
-------------------主线程结束-------------------------Process finished with exit code 0
十七: 线程池技术(ThreadPoolExecutor)
线程池技术认知: 我们知道,线程的创建与销毁都需要销毁系统资源,因此,我们使用线程池来优化线程处理方式 (1)正常线程的使用是: 创建线程,启用,结束,销毁 (2)线程池的处理方式是:程序启动时就会创建若干个线程,并保存在内存中,当线程启动并执行完成之后, 并不销毁处理,而是等待下次在使用。这样内存中的线程就像个池子一样,需要时过来取,用完时就还回去,而不是销毁 在需要频繁创建线程的系统中,一般都会使用线程池技术。原因有两点 (1)每一个线程创建,都需要占用系统资源,是一件相对耗时的事情。同样,在销毁线程时,还需要回收线程资源。线程池技术, 可以省去创建与回收过程中所浪费的系统开销 (2)在某些系统中,需要为每个子任务来创建对应的线程(如爬虫系统中的子链接),这种情况会导致线程数量失控性暴涨,只到程序崩溃. 线程池技术可以很好的固定线程的数量,保持程序稳定.
实例一: 使用串行处理程序与多线程处理同样的程序耗时情况:
# -*- coding:utf-8 -*- from concurrent.futures import ThreadPoolExecutor import time ''' 线程池技术认知: 我们知道,线程的创建与销毁都需要销毁系统资源,因此,我们使用线程池来优化线程处理方式 (1)正常线程的使用是: 创建线程,启用,结束,销毁 (2)线程池的处理方式是:程序启动时就会创建若干个线程,并保存在内存中,当线程启动并执行完成之后, 并不销毁处理,而是等待下次在使用。这样内存中的线程就像个池子一样,需要时过来取,用完时就还回去,而不是销毁 在需要频繁创建线程的系统中,一般都会使用线程池技术。原因有两点 (1)每一个线程创建,都需要占用系统资源,是一件相对耗时的事情。同样,在销毁线程时,还需要回收线程资源。线程池技术, 可以省去创建与回收过程中所浪费的系统开销 (2)在某些系统中,需要为每个子任务来创建对应的线程(如爬虫系统中的子链接),这种情况会导致线程数量失控性暴涨,只到程序崩溃. 线程池技术可以很好的固定线程的数量,保持程序稳定. ''' # 定义线程池处理函数 def printTotalTime(p): print("处理耗时操作 : " + p) # 模拟处理2秒钟 time.sleep(2) person = ["老杨", "老高", "老张"] # 获取开始时间 startTime = time.time() for p in person: printTotalTime(p) endTime = time.time() print("串行处理操作总耗时: %d" % (endTime - startTime), "秒") print() print('----------------------使用并行程序处理统一问题---【抢占式创建线程池】----------------------------') startTime0 = time.time() # 创建抢占式线程池,池内有3个线程 with ThreadPoolExecutor(3) as executor0: for p in person: executor0.submit(printTotalTime, p) # 启用线程 endTime0 = time.time() print("并行处理操作总耗时: %d" % (endTime0 - startTime0), "秒") print() print() print('----------------------使用并行程序处理统一问题---【非抢占式创建线程池】----------------------------') startTime1 = time.time() # 创建抢占式线程池,池内有3个线程 with ThreadPoolExecutor(3) as executor1: for p in person: executor1.map(printTotalTime, p) # 启用线程 endTime1 = time.time() print("并行处理操作总耗时: %d" % (endTime1 - startTime1), "秒") print(""" 总结: 抢占式与非抢占式都可以使用关键字with来创建。不同的是, 非抢占线程是通过调用实例化对象的map方法启用线程;而抢占式式同步submit方法启用线程 """)程序运行效果:
D:\program_file_worker\anaconda\python.exe D:\program_file_worker\python_source_work\SSO\grammar\MultiThreadByThreadPoolExecutorCreateThread.py
处理耗时操作 : 老杨
处理耗时操作 : 老高
处理耗时操作 : 老张
串行处理操作总耗时: 6 秒----------------------使用并行程序处理统一问题---【抢占式创建线程池】----------------------------
处理耗时操作 : 老杨
处理耗时操作 : 老高
处理耗时操作 : 老张
并行处理操作总耗时: 2 秒
----------------------使用并行程序处理统一问题---【非抢占式创建线程池】----------------------------
处理耗时操作 : 老
处理耗时操作 : 杨
处理耗时操作 : 老
处理耗时操作 : 高
处理耗时操作 : 老
处理耗时操作 : 张
并行处理操作总耗时: 4 秒
总结: 抢占式与非抢占式都可以使用关键字with来创建。不同的是,
非抢占线程是通过调用实例化对象的map方法启用线程;而抢占式式同步submit方法启用线程
Process finished with exit code 0