永远不要高估自己
复习内容
操作系统的调度算法:
时间片轮转法
多级反馈队列
同步、异步(描述程序提交任务的方式)
同步:提交任务之后,原地等待任务的执行结果
异步:提交任务之后,不等待任务的执行结果,直接执行下面的代码
阻塞、非阻塞(描述程序的运行状态)
阻塞:遇到IO操作 阻塞态
非阻塞:就绪态/运行态
需要掌握:进程的三状态转换图
进程理论:
创建进程的本质:创建一块独立的内存空间
今日内容
1、进程间通信:IPC机制
2、生产者消费者模型(******)
3、线程理论
4、创建线程的两种方式
5、同一进程下的线程共享进程的所有数据
6、join方法
7、线程对象的其他属性和方法
8、守护线程
9、线程互斥锁
一、进程间通信:IPC机制
队列:先进先出
堆栈:先进后出
利用队列实现进程间的通信
队列的创建:
from multiprocessing import Queue:
q = Queue(3) # 创建了队列对象,并规定只能存储3个数据
'''
# 存取数据
q.put(obj) # 往队列中放入数据
q.put(obj)
q.put(obj)
q.put(obj)
# 由于规定只能存储3个,所以这一行代码会堵塞住,等待从队列中取出一个数据,腾出空间来put数据
'''
q.put_nowait(obj) # 队列不满,跟put一样放入值,一旦队列满了,直接报错,不等待取出
print(q.full()) # 判断队列是否满了,是则True,否则False
'''
res = q.get() # 从队列中取出数据,可以赋值
res = q.get()
res = q.get()
res = q.get()
# 因为队列中只有3个数据,所以这一行代码会堵塞住,等待往队列中put一个数据来get数据
'''
q.get_nowait() # 队列不为空则跟get一样取值,空的话直接报错,不等待put值
print(q.empty()) # 判断队列为不为空,在并发时判断不准确
# 基于队列实现进程间通信 代码示例:
from multiprocessing import Process, Queue
def producer(q):
q.put('hello')
def consumer(q):
print(q.get())
if __name__ == '__main__':
q = Queue()
p1 = Process(target=producer, args=(q, ))
c1 = Process(target=consumer, args=(q, ))
p1.start()
c1.start()
二、生产者消费者模型
生产者:产生数据的对象
消费者:处理数据的对象
将生产数据 与 处理数据 解耦合,处理数据不需要直接与生产数据环节沟通
定义一个队列,生产者将数据存进去,消费者取出来对数据进行处理, 两者通过队列进行沟通
# 代码示例
from multiprocessing import Process, JoinableQueue
import time, random
def produser(name, food, q):
for i in range(1, 6):
food = '%s%s' % (food, i)
time.sleep(random.randint(1, 3))
q.put(food)
print('%s生产了%s' % (name, food))
def consumer(name, q):
while True:
res = q.get()
time.sleep(random.randint(1, 3))
print('%s吃了%s' % (name, res))
q.task_done()
if __name__ == '__main__':
q = JoinableQueue(5)
p1 = Process(target=produser, args=('egon', '包子', q))
p2 = Process(target=produser, args=('owen', '油条', q))
c1 = Process(target=consumer, args=('tank', q))
p1.start()
p2.start()
c1.daemon = True
c1.start()
p1.join()
p1.join()
q.join()
print('主')
三、线程理论
进程是资源单位
线程是执行单位
为什么要有线程:
线程创建时间短
进程需要开辟内存空间和拷贝代码
而线程都不需要
开线程的开销远小于开进程
四、创建线程的两种方式
# 方法一:
from threading import Thread
import time
def task():
print('线程1 is running' )
time.sleep(1)
print('线程1 is done')
t1 = Thread(target=task)
t1.start()
print('主')
# 方法二
from threading import Thread
import time
class MyThread(Thread):
def run(self):
print('线程1 is running' )
time.sleep(1)
print('线程1 is done')
t1 = MyThread()
t1.start()
print('主')
五、同一进程下的线程共享进程的所有数据
测试代码:
from threading import Thread
x = 100
def task():
glbal x
x = 666
print(222, )
t1 = Thread(target=task)
t1.start()
print('主')
run==>
主 666
六、join方法
from threading import Thread
import time
def task():
print('thread1 is running')
time.sleep(2)
print('thread2 is done')
t1 = Thread(target=task)
t1.start()
t1.join()
print('主')
run==>
thread1 is running
thread2 is done
主
七、线程对象的其他属性和方法
from threading import Thread, current_thread, active_count
import os, time
def task(name):
print('%s is running' % name, current_thread().name, current_thread().getName())
time.sleep(1)
print('%s is done' % name)
def info(name):
print('%s is running' % name, current_thread().name, current_thread().getName())
time.sleep(1)
print('%s is done' % name)
t1 = Thread(target=task, args=('egon', ))
t2 = Thread(target=info, args=('owen', ))
t1.start()
t2.start()
t1.join()
print(active_count()) # 查看目前存活的进程
print(os.getpid())
run==>
egon is running Thread-1 Thread-1
owen is running Thread-2 Thread-2
egon is done
owen is done
1
1502
八、守护线程
from threading import Thread
import time
def task(name):
print('%s is running'%name)
time.sleep(1)
print('%s is over'%name)
if __name__ == '__main__':
t = Thread(target=task,args=('王磊',))
# t.daemon = True
t.start()
print('主')
run==>
王磊 is running
主
九、线程互斥锁
from threading import Thread,Lock
import time
mutex = Lock() # 在要操作的数据上上锁
n = 100
def task():
global n
mutex.acquire() # 制定抢锁位置
tmp = n
time.sleep(0.1)
n = tmp -1
mutex.release() # 释放锁
t_list = []
for i in range(100):
t = Thread(target=task)
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(n)