线程概述
进程是cpu资源分配的最小单位,线程是cpu调度的最小单位。
线程必须依托进程存在,同时一个进程内可能含有多个线程,但至少含有一个线程。这个线程叫做主线程!
内核---2个 能跑两个进程
一个进程至少包括一个线程。这个线程叫做主线程
逻辑处理器----4个 就意味着 运用超线程处理技术 可以同时跑4个线程
线程不拥有独立的资源,同一进程内的线程共享同一地址空间(系统资源)
同一个进程中可以包括多个线程,并且线程共享整个进程的资(寄存器、堆、栈、上下文),一个进程至少包括一个线程
一个进程至少包括一个线程。这个线程叫做主线程
子线程
def sing():
for i in range(4):
print('sing')
def dance():
for i in range(4):
print('dance...')
if __name__ == '__main__':
sing()
dance()
# 很显然刚刚的程序并没有完成唱歌和跳舞同时进行的要求
#如果想要实现“唱歌跳舞”同时进行,那么就需要一个新的方法,叫做:多任务 也就是多线程
#线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
#在线看视频:其实是一边从网上下载一边用播放器播放,从进程来讲就一个(咱们打开的网页),其中下载由一个线程管理,播放由一个线程管理,多线程要导入模块
import threading,time
def sing():
for i in range(4):
print('sing...')
time.sleep(3)
print('唱歌结束')
def dance():
for i in range(4):
print('dance...')
time.sleep(3)
print('跳舞结束')
if __name__ == '__main__':
f_sing = threading.Thread(target=sing,name='fufu')
f_dance = threading.Thread(target=dance,name='jianqi')
print(f_sing.getName())
f_sing.setName('jianqi')
print(f_sing.getName())
f_sing.setDaemon(True) #设置守护进程,主线程结束后子线程会关闭
f_dance.setDaemon(True) #设置守护进程,主线程结束后子线程会关闭
f_sing.start() #启动
f_dance.start() #启动
#f_dance.join() #阻塞,子线程执行完才会开始执行下面的代码
#f_sing.join() #阻塞,子线程执行完才会开始执行下面的代码
print('主线程执行完成')
#我们在使用start()这个方法的时候 其实内部调用的run方法
# run方法演示
import time
from threading import Thread
class Myjq(Thread):
def run(self) -> None:
print('hello')
time.sleep(3)
print('bye')
jq = Myjq()
jq.start()
#传参
import time
from threading import Thread
class Myjq(Thread):
def __init__(self,name): #*args,**kwargs
super().__init__() #*args,**kwargs
self.name = name
def run(self) -> None: #->None 可写可不写,本意是里面不需要传值
print('hello{}'.format(self.name))
time.sleep(3)
print('bye')
jq = Myjq("fufu")
jq.start()
#需要继承 需要新的东西 要init 要super
#不继承 需要init
#完全继承 不要新的东西 不需要init
锁
锁
from threading import Thread
a = 1
def f():
global a
a = 356
if __name__ == '__main__':
print(a)
t = Thread(target=f)
t.start()
t.join()
print(a)
这个问题就会涉及到资源的掠夺
from threading import Thread,Lock
a = 1
def f():
global a
lock.acquire() #获取锁
for i in range(1000000):
a += 1
lock.release() #释放锁
def f1():
global a
lock.acquire() # 获取锁
for i in range(1000000):
a -= 1
lock.release() # 释放锁
'''
a += 1
1 先拿到值
2 再进行赋值运算
'''
if __name__ == '__main__':
lock = Lock()
print(a)
t1 = Thread(target=f)
t2 = Thread(target=f1)
t1.start()
t2.start()
t1.join()
t2.join()
print(a)
#死锁:两个线程分别占有一部分资源,并且同时都在等待对方的资源,等待的过程就叫死锁
#互斥锁,乐观锁,悲观锁
#GIL:全局解释锁,单核的情况下实现多任务-并发
'''
python的代码执行由python虚拟机(也叫解释器主循环,CPython版本)来控制,
python在设计之初就考虑到在解释器的主循环中,同时只有一个线程在运行。
即在任意时刻只有一个线程在解释器中运行。对python虚拟机访问的控制由全局解释锁GIL控制,
正是这个锁来控制同一时刻只有一个线程能够运行。
'''
队列
#创建队列(可以指定长度)
from random import randint
from queue import Queue
from threading import Thread
my_q = Queue(10) #容量 队列大小
def f(my_que):
for i in range(10):
num = randint(0,1000)
my_que.put(num) #放任务
def f1(my_que):
for j in range(5):
num = my_que.get()
print(num) #取任务
t1 = Thread(target=f,args=(my_q,))
t2 = Thread(target=f1,args=(my_q,))
t1.start()
t2.start()
t1.join()
t2.join()
my_q.qsize() #查看队列里还剩多少个
-------------------------------------------------------------------------------------------
my.put(1)
print(my.qsize())
my.get()
print(my.qsize())
print(my.empty()) #是否为空
print(my.full()) #是否为满
-------------------------------------------------------------------------------------------
put 是一个任务
my_q.task_done()
队列.join()
主要是给join用的,每次get后需要调用task_done,直到所有任务都task_done.join才取消阻寒
如果线程里每从队列里取一次,但没有执行task_done(),则join无法判断队列到底有没有结束,在最后执行个join()是等不到结果的,会一直挂起。可以理解为,每task_done一次 就从队列里翻掉一个元素,这样在最后join的时候根据队列长度是否为零来判断队列是否结束,从而执行主线程。
my_q.task_done()已默认调用
-----------------------------------------------------------------------------------------
生产者 消费者模式
一个只负责生产 一个只负责消费 实现解耦 高内聚低耦合
阿帕奇 Apache是世界使用排名第一的web服务器软件
恩即克斯 nginx 是一个高性能的HTTP和反向代理web服务器
IIS服务器个称为:Internet Information Services。是微软旗下的web股务器
平衡生产力 和消费力
线程池
概述
更好的利用多线程 出现池 从而提高利用率 可以方便的管理线程,也可以减少内存的消耗。
线程池
线程池,通过有限的几个同定线程为大量的操作服务,减少了创建和销毁线程所需的时间,从而提高效率。
如果一个线程的时间非常长,就没必要用线程池了(不是不能作长时间操作,而是不宜。),况且我们还不能控制线程池中线程的开始、挂起、和中止。
from queue import Queue
from threading import Thread
import time
class TheradPool(object):
'''
创建指定数量的线程池
'''
def __init__(self,n): #线程的数量
self.q = Queue() #放任务的队列
for i in range(n):
Thread(target=self.worker,daemon=True).start() #开始线程
#指向方法 函数名 设置守护进程
def worker(self): #取任务来执行 不需要参数
while True: #一直循环
func = self.q.get() #取任务
func() #执行函数
self.q.task_done() #执行完毕
def put_q(self,func): #放任务
'''
向对象加入要执行的任务函数
'''
self.q.put(func)
def join_q(self):
self.q.join() #阻塞等待任务完成
def task1(): #任务1
print('1go...')
time.sleep(3)
print('lend')
def task2(): #任务2
print('2go...')
time.sleep(3)
print('2end')
def task3(): #任务3
print('3go...')
time.sleep(3)
print('3end')
if __name__ == '__main__':
pool = TheradPool(3) #创建两个线程 进入阻塞 等待任务
pool.put_q(task1()) #发布任务
pool.put_q(task2()) #发布任务
pool.put_q(task3())
print("放任务完成")
pool.join_q() #阻塞
print('任务执行完毕')
如果去掉守护进程 他就会卡在 get()标志着 子线程任务执行不完,
子线程没完成 主线程一直等子线程完成
join 只有在队列不为空时才会阻塞
带参数的线程池
from queue import Queue
from threading import Thread
import time
class TheradPool(object):
'''
创建指定数量的线程池
'''
def __init__(self,n): #线程的数量
self.q = Queue() #放任务的队列
for i in range(n):
Thread(target=self.worker,daemon=True).start() #开始线程
#指向方法 函数名 设置守护进程
def worker(self): #取任务来执行 不需要参数
while True: #一直循环
func,args,kwargs = self.q.get() #取任务
func(*args,**kwargs) #执行函数
self.q.task_done() #执行完毕
def put_q(self,func,*args,**kwargs): #放任务
'''
向对象加入要执行的任务函数
'''
self.q.put((func,args,kwargs)) #变成元组
def join_q(self):
self.q.join() #阻塞等待任务完成
def task1(*args,**kwargs): #任务1
print('1go...')
print(args)
print(kwargs)
time.sleep(3)
print('lend')
def task2(): #任务2
print('2go...')
time.sleep(3)
print('2end')
def task3(): #任务3
print('3go...')
time.sleep(3)
print('3end')
if __name__ == '__main__':
pool = TheradPool(3)
pool.put_q(task1,2,3,4,a = 'hello',b = 'world')
pool.put_q(task2)
pool.put_q(task3)
print("放任务完成")
pool.join_q() #阻塞
print('任务执行完毕')
内置线程池
