线程指的是 进程(运行中的程序)中单一顺序的执行流。
多个独立执行的线程相加 = 一个进程

多线程程序是指一个程序中包含有多个执行流,多线程是实现并发机制的一种有效手段。

每个线程都要经历创建、就绪、运行、阻塞和死亡等5个状态,线程从产生到消失的状态变化称之为生命周期

从图中可以看到,一个线程的生命周期一般经过如下步骤:
 start()方法进入就绪状态,一个处在就绪状态的线程将被调度执行,执行该线程相应的run()方法中的代码。sleep()、wait()、suspent()方法,这个线程进入阻塞状态。一个线程也可能自己完成阻塞操作。run()方法执行完毕,或者有一个例外产生,或者执行 System. exit() 方法,则一个线程就进入死亡状态。| 方法 | 说明 | 
|---|---|
| _ _ init _ _(self,name=threadname) | 初始化方法,threadname为线程名称 | 
| run() | 编写线程代码,实现线程所有要完成的功能 | 
| getName() | 获得线程对象名字 | 
| setName() | 设置线程对象名字 | 
| start() | 启动线程 | 
| jion([timeout]) | 等待另一线程结束后再运行 | 
| setDaemon(bool) | 子线程是否随主线程一起结束,必须在start()之前调用,默认false | 
| isAlive() | 检查线程是否在运行中 | 
Python中,可采用两种方式创建线程:
Thread类的构造函数创建一个多线程对象import threading
def fun(i):
	print("thread id = %d \n" %i)
def main():
	for i in range(1,10):
		t = threading.Thread(target=fun, args=(i,))
		t.start()
		
if __name__ == "__main__":
	main() 
‘‘‘
thread id = 1
thread id = 2
thread id = 5
thread id = 3
thread id = 6
thread id = 4
thread id = 9
thread id = 8
thread id = 7
‘‘‘
Thread类的子类来构造线程,并重写它的run方法import threading
import time
 
# 定义线程子类
class MyThread(threading.Thread):
	def __init__(self): #, func, args, name=‘‘):
		threading.Thread.__init__(self)
		#self.func = func
		#self.args = args
		#self.name = name
	def run(self):
		print("starting", self.name)
def main():
	t1 = MyThread()
	t1.start()
	t2 = MyThread()
	t2.start()
if __name__ == "__main__":
	main() 
 
‘‘‘
starting Thread-1
starting Thread-2
‘‘‘
我们用Thread子类程序来模拟航班售票系统,实现二个售票窗口发售某班次航班的10张机票,一个售票窗口用一个线程来表示。
import threading
import time
 
# 定义线程子类 
class MyThread(threading.Thread):
    tickets = 10
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        while(1):
            if(self.tickets>0):
                self.tickets = self.tickets-1
                print(self.name,"售机票售出第",self.tickets, " 号")
            else:
                exit()
def main():
    t1 = MyThread()
    t1.start()
    t2 = MyThread()
    t2.start()
if __name__ == "__main__":
    main() 
‘‘‘
Thread-1 售机票售出第 9  号
Thread-1 售机票售出第 8  号
Thread-1 售机票售出第 7  号
Thread-2 售机票售出第 9  号
Thread-1 售机票售出第 6  号
Thread-2 售机票售出第 8  号
Thread-1 售机票售出第 5  号
Thread-2 售机票售出第 7  号
Thread-1 售机票售出第 4  号
Thread-2 售机票售出第 6  号
Thread-1 售机票售出第 3  号
Thread-2 售机票售出第 5  号
Thread-1 售机票售出第 2  号
Thread-2 售机票售出第 4  号
Thread-1 售机票售出第 1  号
Thread-1 售机票售出第 0  号
Thread-2 售机票售出第 3  号
Thread-2 售机票售出第 2  号
Thread-2 售机票售出第 1  号
Thread-2 售机票售出第 0  号
‘‘‘
从运行结果中可以看到,每张机票被卖了2次,即2个线程各自卖10张机票,而不是去卖共同的10张机票。为什么会这样呢?我们需要的是,多个线程去处理同一资源,一个资源只能对应一个对象。而在上面的程序中,我们创建了2个MyThread对象,每个MyThread对象中都有10张机票,每个线程都在独立地处理各自的资源。
我们用Thread类的构造函数创建的线程程序来模拟航班售票系统,实现二个售票窗口发售某班次航班的10张机票,一个售票窗口用一个线程来表示。
import threading
global tickets
tickets= 11
def fun(i):
	global tickets
	while(tickets>1):
		tickets = tickets-1
		print("第", i,"售机票窗口售出第",tickets, " 号")
def main():
	for i in range(1,3):
		t = threading.Thread(target=fun, args=(i,))
		t.start()
if __name__ == "__main__":
	main()
‘‘‘
第 1 售机票窗口售出第 10 号
第 1 售机票窗口售出第 9  号
第 1 售机票窗口售出第 8  号
第 1 售机票窗口售出第 6  号
第 2 售机票窗口售出第 7  号
第 1 售机票窗口售出第 5  号
第 2 售机票窗口售出第 4  号
第 1 售机票窗口售出第 3  号
第 2 售机票窗口售出第 2  号
第 1 售机票窗口售出第 1  号
‘‘‘
在上面的程序中,创建了2个线程,每个线程调用的是同一个Thread对象中的fun()方法,访问的是同一个对象中的变量(tickets)的实例。因此,这个程序能满足我们的要求。
多线程使用不当可能造成数据混乱。例如,两个线程都要访问同一个共享变量,一个线程读这个变量的值并在这个值的基础上完成某些操作,但就在此时,另一个线程改变了这个变量值,但第一个线程并不知道,这可能造成数据混乱。
下面模拟二个用户从银行取款的操作造成数据混乱的一个例子。
设计一个模拟用户从银行取款的应用程序。设某银行帐户存款额的初值是2000元,用线程模拟两个用户从银行取款的情况。
import threading
import time
#定义银行帐户类 
class Mbank:
	global sum
	sum=2000
	def take(k):
		global sum
		temp=sum
		temp=temp - k
		time.sleep(0.2)
		sum = temp
		print("sum=",sum)
# 模拟用户取款的线程子类 
class MyThread(threading.Thread):
    tickets = 10
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        for i in range(1,5):  #循环四次
            Mbank.take(100)
def main():
    t1 = MyThread()
    t1.start()
    t2 = MyThread()
    t2.start()
if __name__ == "__main__":
    main() 
‘‘‘
sum= 1900
sum= 1900
sum= 1800
sum= 1800
sum= 1700
sum= 1700
sum= 1600
sum= 1600
‘‘‘
我们该如何解决呢?
使用同步线程是为了保证在一个进程中多个线程能协同工作,所以线程的同步很重要。所谓线程同步就是在执行多线程任务时,一次只能有一个线程访问共享资源,其他线程只能等待,只有当该线程完成自己的执行后,另外的线程才可以进入。
使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire()方法和release()方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。
用线程同步的方法重新设计用户从银行取款的应用程序。
import threading
import time
threadLock = threading.Lock() #创建一个锁对象
#定义银行帐户类 
class Mbank:
	global sum
	sum=2000
	def take(k):
		global sum
		temp=sum
		temp=temp - k
		time.sleep(0.2)
		sum = temp
		print("sum=",sum)
# 模拟用户取款的线程子类 
class MyThread(threading.Thread):
	tickets = 10
	def __init__(self):
		threading.Thread.__init__(self)
	def run(self):
		for i in range(1,5):
			threadLock.acquire() #获得锁 
			Mbank.take(100)
			threadLock.release() #释放锁
def main():
    t1 = MyThread()
    t1.start()
    t2 = MyThread()
    t2.start()
if __name__ == "__main__":
    main() 
‘‘‘
sum= 1900
sum= 1800
sum= 1700
sum= 1600
sum= 1500
sum= 1400
sum= 1300
sum= 1200
‘‘‘
不严重的错误我们称之异常。(如:3/0)
Python标准常见异常(网上摘抄滴):
| 异常名称 | 描述 | 
|---|---|
| BaseException | 所有异常的基类 | 
| SystemExit | 解释器请求退出 | 
| KeyboardInterrupt | 用户中断执行(通常是输入^C) | 
| Exception | 常规错误的基类 | 
| StopIteration | 迭代器没有更多的值 | 
| GeneratorExit | 生成器(generator)发生异常来通知退出 | 
| StandardError | 所有的内建标准异常的基类 | 
| ArithmeticError | 所有数值计算错误的基类 | 
| FloatingPointError | 浮点计算错误 | 
| OverflowError | 数值运算超出最大限制 | 
| ZeroDivisionError | 除(或取模)零 (所有数据类型) | 
| AssertionError | 断言语句失败 | 
| AttributeError | 对象没有这个属性 | 
| EOFError | 没有内建输入,到达EOF 标记 | 
| EnvironmentError | 操作系统错误的基类 | 
| IOError | 输入/输出操作失败 | 
| OSError | 操作系统错误 | 
| WindowsError | 系统调用失败 | 
| ImportError | 导入模块/对象失败 | 
| LookupError | 无效数据查询的基类 | 
| IndexError | 序列中没有此索引(index) | 
| KeyError | 映射中没有这个键 | 
| MemoryError | 内存溢出错误(对于Python 解释器不是致命的) | 
| NameError | 未声明/初始化对象 (没有属性) | 
| UnboundLocalError | 访问未初始化的本地变量 | 
| ReferenceError | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 | 
| RuntimeError | 一般的运行时错误 | 
| NotImplementedError | 尚未实现的方法 | 
| SyntaxError | Python 语法错误 | 
| IndentationError | 缩进错误 | 
| TabError | Tab 和空格混用 | 
| SystemError | 一般的解释器系统错误 | 
| TypeError | 对类型无效的操作 | 
| ValueError | 传入无效的参数 | 
| UnicodeError | Unicode 相关的错误 | 
| UnicodeDecodeError | Unicode 解码时的错误 | 
| UnicodeEncodeError | Unicode 编码时错误 | 
| UnicodeTranslateError | Unicode 转换时错误 | 
| Warning | 警告的基类 | 
| DeprecationWarning | 关于被弃用的特征的警告 | 
| FutureWarning | 关于构造将来语义会有改变的警告 | 
| OverflowWarning | 旧的关于自动提升为长整型(long)的警告 | 
| PendingDeprecationWarning | 关于特性将会被废弃的警告 | 
| RuntimeWarning | 可疑的运行时行为(runtime behavior)的警告 | 
| SyntaxWarning | 可疑的语法的警告 | 
| UserWarning | 用户代码生成的警告 | 
(1)使用try...except语句:
?        try:
		<被检测的语句块>       
except <异常类型名称>:
		<处理异常的语句块>      
例如:元组下标越界引发异常
s=[1,2,3,4,5]
try:
	print(s[5])
except IndexError:
	print("索引出界")
‘‘‘
发生异常原因:索引出界
‘‘‘
(2)使用try...except...else语句:
try:
		<被检测的语句块>       
except <异常类型名称>:
		<处理异常的语句块>      
 else:
		<无异常时执行的语句块> 
例如:编写程序,从键盘输入1,2,……,5中的一个数字,否则,当输入其他数字或字符则提示为异常。
s=[1,2,3,4,5]
while True:
	try:
		i = eval(input(‘input:‘))
		print(s[i])
	except IndexError:
		print("发生异常原因:索引出界")
		break
	except NameError:
		print("发生异常原因:不是数字")
		break
	except KeyboardInterrupt:
		print("发生异常原因:用户中断输入")
		break
	else:
		pass

(3)带有finally子句的try语句:
s=input("请输入你的年龄:")
if s =="":
	raise Exception("输入不能为空.") 
try: 
	i=int(s)
except Exception as err:
	print(err) 
finally: 
	print("Goodbye!") 
我们先从简单的问题开始。假设要搜索一个包含字符“cat”的字符串,搜索用的子字符串就是“cat”。如果搜索对大小写不敏感,单词“catalog”、“Catherine”、“sophisticated”都可以匹配。也就是说:
子字符串:cat
匹配:catalog、Catherine、sophisticated
例如,使用?和*通配符来查找硬盘上的文件。?通配符匹配文件名中的1个字符,而*通配符匹配多个字符。这时,?和*通配符就是一种匹配模式。
比如,data?.dat这样的模式将查找下列文件:
data.dat
data1.dat
data2.dat
datax.dat
dataN.dat
若使用*字符代替?字符扩大了找到的文件的数量。data*.dat匹配下列所有文件:
data.dat
data1.dat
data2.dat
data12.dat
datax.dat
dataXYZ.dat
正则表达式是一种可以用于模式匹配和替换的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。一个正则表达式就是由普通的字符(例如字符‘a’~‘z’)以及特殊字符(称为“元字符”)组成的文字模式。该模式用以描述在查找文字主体时待匹配的一个或多个字符串。
正则表达式的使用,可以通过简单的办法来实现强大的功能。
下面先看一个简单的用特殊字符(元字符)表示正则表达式规则的示例:
^ [ 0 – 9 ] + abc$
其中:
^ 匹配字符串的开始位置。
[0-9]+ 匹配多个数字, [0-9]匹配单个数字,+匹配一个或者多个。
abc$匹配字母 abc 并以“abc”结尾
$为匹配输入字符串的结束位置。
该规则表示,需要匹配以数字开头并以“abc”结尾的字符串。
编写程序,匹配以数字开头,并以“abc”结尾的字符串。
import re
str = r"123abc"   # 需要匹配的源文本
p1 = r"^[0-9]+abc$"  # 编写正则表达式规则
patt1 = re.compile(p1)    # 编译正则表达式
matc1 = re.search(patt1, str)  # 在源文本看搜索符合正则表达式的部分
print(matc1.group(0)) # 123abc 

匹配的流程如下:

正则表达式re模块提供了正则表达式操作所需要的方法,利用这些方法,可以很方便地得到匹配结果。

group()用于获取子模式(组)的匹配项。
例如:
pat = re.compile(r‘www\.(.*)\.(.*)‘)  # 用()表示1个组,这里定义2个组
m = pat.match(‘www.dxy.com‘)
m.group()     # 默认值为0,表示匹配整个字符串,返回‘www.dxy.com‘
m.group(1)    # 返回给定组1匹配的子字符串‘dxy‘
m.group(2)    # 返回给定组2匹配的子字符串‘com‘
start()为指定组匹配项的开始位置
例如:
m.start(2) # 组2开始的索引,返回值为8
end()为指定组匹配项的结束位置
例如:
  m.end(2)  # 组2结束的索引,返回值为11
小案例演示:
编译正则表达式,创建模式对象示例
import re
pat=re.compile(‘A‘)  #编译正则表达式
m=pat.search(‘CBA‘)  #等价于 re.search(‘A‘,‘CBA‘)
print(m)
#匹配到了,返回<_sre.SRE_Match object: span=(2, 3)> 
m=pat.search(‘CBD‘)
print(m)
#没有匹配到,返回None(False)

在一个字符串中查找子串示例
#第一步,要引入re模块
import re   
#第二步,调用模块函数
a = re.findall("我在吃大西瓜呢", "博客园的我在吃大西瓜呢正在准备考研,他要考计算机专业")
print(a)  #以列表形式返回匹配到的字符串

应用多线程,编写一个“幸运大转盘”抽奖游戏程序。
 ######################
 #幸运大转盘          #
 ######################
import tkinter
import time
import threading
root = tkinter.Tk()
root.title(‘“幸运大转盘”抽奖游戏‘)
root.minsize(300,300)
btn1 = tkinter.Button(text = ‘奔驰‘,bg = ‘red‘)
btn1.place(x = 20, y = 20, width = 50, height = 50)
btn2 = tkinter.Button(text = ‘宝马‘,bg = ‘white‘)
btn2.place(x = 90, y = 20, width = 50, height = 50)
btn3 = tkinter.Button(text = ‘奥迪‘,bg = ‘white‘)
btn3.place(x = 160, y = 20, width = 50, height = 50)
btn4 = tkinter.Button(text = ‘日产‘,bg = ‘white‘)
btn4.place(x = 230, y = 20, width = 50, height = 50)
btn5 = tkinter.Button(text = ‘宾利‘,bg = ‘white‘)
btn5.place(x = 230, y = 90, width = 50, height = 50)
btn6 = tkinter.Button(text = ‘劳斯‘,bg = ‘white‘)
btn6.place(x = 230, y = 160, width = 50, height = 50)
btn7 = tkinter.Button(text = ‘奇瑞‘,bg = ‘white‘)
btn7.place(x = 230, y = 230, width = 50, height = 50)
btn8 = tkinter.Button(text = ‘吉利‘,bg = ‘white‘)
btn8.place(x = 160, y = 230, width = 50, height = 50)
btn9 = tkinter.Button(text = ‘大众‘,bg = ‘white‘)
btn9.place(x = 90, y = 230, width = 50, height = 50)
btn10 = tkinter.Button(text = ‘沃尔沃‘,bg = ‘white‘)
btn10.place(x = 20, y = 230, width = 50, height = 50)
btn11 = tkinter.Button(text = ‘红旗‘,bg = ‘white‘)
btn11.place(x = 20, y = 160, width = 50, height = 50)
btn12 = tkinter.Button(text = ‘长城‘,bg = ‘white‘)
btn12.place(x = 20, y = 90, width = 50, height = 50)
#将所有选项组成列表
carlist = [btn1,btn2,btn3,btn4,btn5,btn6,btn6,btn7,btn8,btn9,btn10,btn11,btn12]
#是否开始循环的标志
isloop = False
def round():
     #判断是否开始循环
    if isloop == True:
         return
     #初始化计数   变量
    i = 0
     #死循环
    while True:
        time.sleep(0.1)
        #将所有的组件背景变为白色
        for x in carlist:
             x[‘bg‘] = ‘white‘
        #将当前数值对应的组件变色
        carlist[i][‘bg‘] = ‘red‘
        #变量+1
        i += 1
        #如果i大于最大索引直接归零
        if i >= len(carlist):
             i = 0
        if functions ==True :
             continue
        else :
             break
 #“开始”按钮事件:建立一个新线程的函数。
def newtask():
     global isloop
     global functions
     #建立新线程
     t = threading.Thread(target= round)
     #开启线程运行
     t.start()
     #设置程序开始标志
     isloop = True
     #是否运行的标志
     functions = True
 #“停止”按钮事件:停止循环
def stop():
     global isloop
     global functions
     functions = False
     isloop = False
 #开始按钮
btn_start = tkinter.Button(root,text = ‘开始‘,command = newtask)
btn_start.place(x = 90, y = 120, width = 50, height = 50)
btn_stop = tkinter.Button(root,text = ‘停止‘,command = stop)
btn_stop.place(x = 160, y = 120, width = 50, height = 50)
root.mainloop() 

下节课要讲,很是期待啊,大学都是学Javaweb了,从来没有尝试去接触大数据学习。
大数据(Big Data)有5大特性:volume(大量)、velocity(高速)、variety(多样)、value(低价值密度)、veracity(真实性)
一些准备,下载以下三个库,网速慢就找三方库:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 库名
数据挖掘: jieba  (分析《三国演义》人物出场次数统计)
数据可视化:numpy、pandas、matplotlib   (霍兰德“人格分析”雷达图)
虽然网上可能很早就有了,但是毕竟是入门,值得期待。
原文:https://www.cnblogs.com/wangzheming35/p/12837357.html