为了解决在一个程序中多个函数或多处地方一起执行一起执行的问题
线程:就是实现多任务的一种手段 在一个程序运行起来以后一定有一个执行代码东西 这个东西就叫做线程
主要思路:
先创建一个theading.Thread()的实例对象 并给出实例对象的参数 也就是创造一个子线程
用实例对象调用start()方法
threading.Thread(target=def,args=parameter)
def 表示将来,这个线程去哪个函数执行代码
parameter 表示指定将来调用 函数的时候 传递什么参数过去 一定时个元组 不是元组程序壁
例 代码
import time
import threading
#创建测试函数 sing
def sing():
for i in range(5):
print("--------正在唱歌------")
time.sleep(1)
#创建测试函数dunce
def dunce():
for i in range(5):
print("-------正在跳舞--------")
time.sleep(1)
def main():
#创建第一个Thread对象 t1 并将测试函数sing 的函数名一参数给如Thread方法
t1 = threading.Thread(target=sing)
#创建第二个Thread对象 t2 并将测试函数dunce 的函数名一参数给如Thread方法
t2 = threading.Thread(target=dunce)
#t1 t2 调用start放方法开始执行子进程
t1.start()
t2.start()
if __name__ == "__main__":
main()
输出结果:
--------正在唱歌------
-------正在跳舞--------
--------正在唱歌------
-------正在跳舞--------
--------正在唱歌------
-------正在跳舞--------
--------正在唱歌------
-------正在跳舞--------
-------正在跳舞--------
--------正在唱歌------
当主进程没有代码执行时,会等待子进程执行结束
子线程实在threading.Thread创建的实例对象调用此对象的start()时创建和开始工作的
子线程的死亡时间时是子线程执行的程序结束的时间
当主进程结束时,整个程序也就结束了
若在执行中主线程先死亡,子线程也会跟着死
查看程序中一共有多少线程 threading.enumerate
进程执行没有先后 想控制线程的执行先后可以控制线程的延迟达到控制线程的先后
Tread调用类
1这个类必须继承于threading.Thread
2必须要存在run函数
import time
import threading
class Modle(threading.Thread):
def run(self):
for i in range(3):
time.sleep(1)
print("1---")
if __name__ == "__main__":
t = Modle()
t.start()
执行结果:
1—
1—
1—
在调用类时 调用start方法时会自动调用类当中run方法
调用类适合于一个线程中做的事情比较复杂 在一个类中分成多个函数使用
在创建的对象中调用start方法时只会执行一个run方法 让其余的方法被run方法调用
子线程之间共享全局变量
互斥锁 threading.Lock
当多个线程几乎同时四u该某一个共享数据的时候,需要进行同步控制
线程同步能够保证多个线程安全访问竞争资源,最简单的机制时引入互斥锁
互斥锁为资源引入一个状态:锁定/非锁定
某个线程要更改共享数据时,先将其锁定,此时i资源进入锁定状态,其他相乘不能惊醒更改:知道该线程释放资源,将资源改成非锁定,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程下数据的正确性
#创建互斥锁
mutex = threading.Lock()
#锁定
mutex.acqurie()
#释放(互斥锁解锁)
mutex.release()
例:解决 ------共享全局变量资源竞争
#没上互斥锁的情况
import time
import threading
g_num = 0
def test1(num):
global g_num
for i in range(num):
g_num += 1
print("----------1-----------")
def test2(num):
global g_num
for i in range(num):
g_num += 1
print("----------2-----------")
def main():
t1 = threading.Thread(target=test1, args=(1000000,))
t2 = threading.Thread(target=test2, args=(1000000,))
t1.start()
t2.start()
time.sleep(5)
print("%d" % g_num)
if __name__ == "__main__":
main()
代码执行结果:
----------1-----------
----------2-----------
1146329
由于在运行过程中test1的执行结果纷纷为三个步骤
1.取到全局变量g_num变量
2.让全局变量g_num加1
3.把全局变量放回内存
由于在执行中cpu时让每一个线程执行一会
所以在全局变量未放回内存中时执行了另一个线程所以会有全局变量的资源竞争
产生了+1冲突 重复累加 而产生计算结果错误
用互斥锁就可以解决此问题
解决方法1
#采用互斥锁
import time
import threading
g_num = 0
# 创建一个互斥锁
mutex = threading.Lock()
def test1(num):
global g_num
# 上锁,如果没有上锁,此时上锁成功
# 如果上锁之前,已经被上锁,则会堵塞在这里,直到这个锁被解开
mutex.acquire()
for i in range(num):
g_num += 1
# 解锁
mutex.release()
print("----------1-----------")
def test2(num):
global g_num
mutex.acquire()
for i in range(num):
g_num += 1
mutex.release()
print("----------2-----------")
def main():
t1 = threading.Thread(target=test1, args=(1000000,))
t2 = threading.Thread(target=test2, args=(1000000,))
t1.start()
t2.start()
time.sleep(5)
print("%d" % g_num)
if __name__ == "__main__":
main()
输出结果:
----------1-----------
----------2-----------
2000000
解决方法2
import time
import threading
g_num = 0
# 创建一个互斥锁
mutex = threading.Lock()
def test1(num):
global g_num
for i in range(num):
# 上锁,如果没有上锁,此时上锁成功
# 如果上锁之前,已经被上锁,则会堵塞在这里,直到这个锁被解开
mutex.acquire()
g_num += 1
# 解锁
mutex.release()
print("----------1-----------")
def test2(num):
global g_num
for i in range(num):
mutex.acquire()
g_num += 1
mutex.release()
print("----------2-----------")
def main():
t1 = threading.Thread(target=test1, args=(1000000,))
t2 = threading.Thread(target=test2, args=(1000000,))
t1.start()
t2.start()
time.sleep(5)
print("%d" % g_num)
if __name__ == "__main__":
main()
执行结果:
----------2-----------
----------1-----------
2000000
互斥锁锁定的代码尽量短
否则可能产生由于某一个代码片段延迟过高而降低整体的运行速度
在一个代码快中 若存在太多的互斥锁 则有可能出现死锁的情况
在设计程序时要尽量避免死锁
添加超时时间等