标签:time run lang 含义 并且 主线程 完成 总结 行操作
多任务含义:
并发和并行
进程:正在运行的一个程序我们可以说是一个进程 ,是系统进行资源分配和调用的独立单元,每 一个进程都有自己独立的内存空间和系统资源
程序:运行起来的应用程序就称之为进程。也就是说当程序不运行的时候我们称之为程序, 当程序运行起来他就是一个进程。通俗的理解就是不运行的时候是程序,运行起来就是进程。 程序只有一个,但是进程可以有多个
线程:线程是进程中的一条执行线路或者流程,程序执行的最小单位,线程是任务调度的最小单 位。
进程和线程关系:一个进行可以有一个或者多个线程,但是一个线程只属于一个进程,一个进程中的多个线程是一种竞争关系
?
#一边下载歌曲,一边听歌
import time
import threading
def listen():
for i in range(1,6):
print("正在听歌")
time.sleep(1)
def down_load():
for i in range(1,6):
print("正在下载歌曲")
time.sleep(1)
# down_load()
# sing()
if __name__ == ‘__main__‘:
#创建线程
t1 = threading.Thread(target=down_load)
t2 = threading.Thread(target=listen)
#执行线程
t1.start()
t2.start()
执行顺序:首先程序运行时,程序从上往下走,遇到if __name__ == ‘__main__‘:,创建了两条线程,我们称之为子线程,程序运行时的线程我们称之为主线程
然后子线程根据target=xxx,开始执行指定的函数
线程注意点
线程何时开启,何时结束
1.子线程何时开启,何时运行
当调用start()时,开启线程,在运行线程的代码
2.子线程何时结束
子线程把target指向的函数中的语句执行完毕,当前子线程结束
3.查看线程数量
通过threading.enumerate()可以枚举当前运行的所有线程
4.主线程何时结束
所有子线程执行完毕后,主线程才结束
查看线程执行情况
import threading
import time
def test1():
for i in range(1,6):
time.sleep(1)
print("--子线程1--%d"%i)
print("子线程1中查看线程情况:",threading.enumerate())
def test2():
for i in range(1,6):
time.sleep(1)
print("--子线程2--%d"%i)
print("子线程2中查看线程情况:",threading.enumerate())
def main():
print("创建线程之前的线程情况:",threading.enumerate())
#创建线程
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
time.sleep(1)
print("创建线程之后的线程情况:", threading.enumerate())
#开启线程
t1.start()
t2.start()
time.sleep(1)
print("调用start之后的线程情况:", threading.enumerate())
time.sleep(6)
print("等待子线程执行结束后的线程情况:", threading.enumerate())
if __name__ == ‘__main__‘:
main()
args传参
给函数传递参数,使用线程关键字args=( )进行传递参数,传递的参数是一个元组
import time
import threading
def listen(num):
for i in range(1,num):
print(f"正在听歌--{i}")
time.sleep(1)
def down_load(num):
for i in range(1,num):
print(f"正在下载歌曲--{i}")
time.sleep(1)
def main():
t1 = threading.Thread(target=down_load,args=(5,))
t2 = threading.Thread(target=listen,args=(3,))
t1.start()
t2.start()
if __name__ == ‘__main__‘:
main()
join()方法
功能:当前线程执行完之后,其他线程才会继续执行
import time
import threading
def listen(num):
for i in range(1,num):
print(f"正在听歌--{i}")
time.sleep(1)
def down_load(num):
for i in range(1,num):
print(f"正在下载歌曲--{i}")
time.sleep(1)
def main():
#下载完歌曲,才可以听歌
t1 = threading.Thread(target=down_load,args=(5,))
t2 = threading.Thread(target=listen,args=(5,))
t1.start()
t1.join() #在t1执行完之后,t2和主线程才执行
t2.start()
t2.join() # 在t1,t2执行完后,再继续执行主线程
if __name__ == ‘__main__‘:
main()
print("程序执行结束了")
setDaemon()将当前线程设置成守护线程,来守护主线程
当主线程结束后,守护线程也就结束,不管是否执行完成,即主线程结束后不等待守护线程,立即结束
应用场景:qq多个聊天窗口,就可以设置为守护线程
#一边下载歌曲,一边听歌
import time
import threading
def listen():
for i in range(1,6):
print("正在听歌")
time.sleep(1)
def down_load():
for i in range(1,6):
print("正在下载歌曲")
time.sleep(0.5)
def main():
#创建线程
t1 = threading.Thread(target=down_load)
t2 = threading.Thread(target=listen)
# t1.setDaemon(True)
t2.setDaemon(True)
# 开启线程
t1.start()
t2.start()
if __name__ == ‘__main__‘:
main()
print("程序执行结束了")
threading模块提供的方法
threading.currentThread():返回当前的线程变量
threading.enumerate():返回一个包含所有正在运行的线程list。正在运行的线程:启动后,结束前,不包括启动前和终止后的线程
threading.activeCount():返回正在运行的线程数量,与len(threading.enumerate())有相同的结果
线程.getName():获取线程名称
线程.setName():设置线程名称
线程.is_alive():判断线程存活状态
定义一个类继承threading.Thread
复写父类的run()方法
import threading
import time
class MyThread(threading.Thread):
def run(self):
for i in range(3):
time.sleep(1)
msg = f"I‘m {self.name} @{i}"
print(msg)
def test1():
for i in range(5):
#创建线程
t = MyThread()
#开启线程
t.start()
def main():
test1()
main()
import threading
import time
g_num = 100
def work1():
global g_num
for i in range(3):
g_num+=1
print(f"--in work1,g_num is {g_num}")
def work2():
global g_num
print(f"--in work2,g_num is {g_num}")
print("创建线程之前g_num:",g_num)
t1 = threading.Thread(target=work1)
t1.start()
time.sleep(1)
t2 = threading.Thread(target=work2)
t2.start()
def work1(g_nums):
g_nums.append(44)
print(f"--in work1,g_num is {g_nums}")
def work2(g_nums):
time.sleep(0.5)
print(f"--in work2,g_num is {g_nums}")
g_nums = [11,22,33]
t1 = threading.Thread(target=work1,args=(g_nums,))
t1.start()
t2 = threading.Thread(target=work2,args=(g_nums,))
t2.start()
多线程开发可能会遇到的问题
t1,t2两个线程都要对全局变量g_num(默认是0)进行加1运算,t1和t2都各对g_num 加10次,那么g_num的最终结果应该是20
但是由于是多线程同时操作,可能会出现以下情况:
在g_num=0时,t1取的g_num=0,此时系统把t1调为“sleeping”状态,把t2转换为“running”状态,t2也获得g_num=0
然后t2对得到的值进行加1操作并赋值给g_num,使得g_num=1
然后系统又把把t2转换为“sleeping”状态,把t1调为“running”状态,线程t1把之前获取到0加1后赋值给g_num,使用g_num=1
这样导致虽然t1和t2都对g_num 加1,但结果仍是g_num=1
g_num = 0
def work1(num):
global g_num
for i in range(num):
g_num+=1 #g_num=g_num+1
print(f"--in work1,g_num is {g_num}")
def work2(num):
global g_num #work1执行10次执行切换到work2
for i in range(num):
g_num+=1 #g_num=g_num+1
print(f"--in work2,g_num is {g_num}")
print("创建线程之前g_num:",g_num)
t1 = threading.Thread(target=work1,args=(100,))
t1.start()
t2 = threading.Thread(target=work2,args=(100,))
t2.start()
#如果多个线程对同一个全局变量进行操作,会出现资源竞争,从而数据不准确,即会遇到线程安全问题
当多个线程几乎同时修改一个共享数据的时候,需要进行同步控制,线程同步能够保证多个 线程安全的访问竞争资源(全局内容),最简单的同步机制就是使用互斥锁
互斥锁为资源引入的一个状态:锁定/非锁定
使用过程:当某个线程要更改共享数据时,先将其锁定,此时资源的状态是“锁定”,其他线程不能访问,直到该线程释放资源,将资源改为“非锁定”状态,其他线程才可以再次锁定该资源。
import threading
#创建锁
mutex = threading.Lock()
#锁定
mutex.acquire()
#释放
mutex.release()
注意:如果这个锁之前没有上锁,那么acquire不会堵塞
如果在调用acquire 对这个锁上锁之前,他已经被其他线程上了锁,此时acquire会堵塞,直到锁被解锁位置
#使用互斥锁完成2个线程对同一全局变量各加100万次操作
g_num = 0
def work1(num):
global g_num
for i in range(num):
# 锁定
mutex.acquire()
g_num+=1
# 释放
mutex.release()
def work2(num):
global g_num #work1执行10次执行切换到work2
for i in range(num):
# 锁定
mutex.acquire()
g_num += 1
# 释放
mutex.release()
#创建锁
mutex = threading.Lock()
t1 = threading.Thread(target=work1,args=(1000000,))
t1.start()
t2 = threading.Thread(target=work2,args=(1000000,))
t2.start()
while len(threading.enumerate())!=1:
time.sleep(1)
print(f"--最终结果,g_num is {g_num}")
在多个线程共享资源的时候,如果两个线程分别占有一部分资源,并且同时等待对方的资源, 就会造成死锁现象,尽管死锁很少发生,但是一旦发生就会造成应用程序停止相应
import time
def test1():
#lock1上锁
lock1.acquire()
print("--test1开始执行--")
time.sleep(1)
# lock2上锁
lock2.acquire()
print("--test1执行完成--")
lock2.release() #lock2解锁
lock1.release() #lock1解锁
def test2():
# lock2上锁
lock2.acquire()
print("--test2开始执行--")
time.sleep(1)
# lock1上锁
lock1.acquire()
print("--test2执行完成--")
lock1.release() # lock1解锁
lock2.release() # lock2解锁
lock1 = threading.Lock()
lock2 = threading.Lock()
if __name__ == ‘__main__‘:
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
t1.start()
t2.start()
总结 :在多线程开发中,全局变量是多个线程都共享的数据,而局部变量等是各自线程的,是非共 享的
队列:Python 的 Queue 模块中提供了同步的、线程安全的队列类,包括 FIFO(先入先出)队列 Queue, LIFO(后入先出)队列 LifoQueue,和优先级队列 PriorityQueue。这些队列都实现了锁原语 (可以理解为原子操作,即要么不做,要么就做完),能够在多线程中直接使用。可以使用 队列来实现线程间的同步
from queue import Queue
#1.创建队列对象
# q = Queue(maxsize=3) #3表示最多存放3个数据
#参数maxsize 是队列中允许的最大项,如果省略次参数,则无大小限制,
#返回值q是队列对象
# 2.put()方法 , 项队列中存放数据 如果q为空,此方法阻塞,直到队列可用为止
# 3.get()方法 ,返回队列中的一个项目,如果队列为空,此方法阻塞,直到队列可用为止
# 4.get_nowait(), 不等待,直接抛出异常
# 5.full() , 如果q已满,返回True
# 6.empty(), 如果q已空,返回True
# 7.qsize(), q中数据的个数
q = Queue(maxsize=3)
q.put("张伟强")
# print(q.empty())
q.put("刘江")
q.put("张威")
print(q.full())
# q.put("徐伟明")
print(q.get())
print(q.get())
print(q.get())
# print(q.get(timeout=3))
# print(q.get_nowait())
print(q.qsize())
生产者与消费者模式
生产者:生产数据的线程
消费者:处理数据的线程
目的:平衡生产者和消费者的工作能力来提高程序的整体处理数据的速度
import threading
import queue
import time
def producer(name): #生产者
count = 1
while True:
print("%s生产了包子%d"%(name,count))
q.put(count)
count+=1
time.sleep(0.2)
print("包子总数",q.qsize())
def costom(name): #消费者
while True:
print("%s吃了包子%d"%(name,q.get()))
time.sleep(1)
if __name__ == ‘__main__‘:
q = queue.Queue(maxsize=3)
t1 = threading.Thread(target=producer,args=("张大厨",))
t2 = threading.Thread(target=costom, args=("吃货刘",))
t3 = threading.Thread(target=costom, args=("吃货朱",))
t1.start()
t2.start()
t3.start()
为什么使用生产者和消费者模式
什么是生产者消费者模式
标签:time run lang 含义 并且 主线程 完成 总结 行操作
原文地址:https://www.cnblogs.com/markshui/p/12895998.html