第十三节课:多线程

第十三节课:多线程


一、 线程

线程也叫轻量级线程,是操作系统能够进行运算调度的最小单位,包含在进程中,是进程中实际运行单位。

二、为什么使用多线程:

多线程是多礼的并发的执行流,能够共享数据,文件,句柄和内存,不用开辟新的储存空间,比进程有更好的效率

三.线程的实现:threaing模块

1.自定义编程:

继承threading.Thread 重构run方法

2.守护线程:

子线程会随着主线程的结束而结束(不管子线程是否运行完)
主线程等待子线程的方法:.join
多线程共享全局变量:在同一个进程中多线程是共享资源的。

3.互斥锁:

多个线程同士修改统一数据是可能出现脏数据,为了防止这一情况,设计了互斥锁,同一时刻只允许一个线程执行操作
获取锁:lock.acquire()
释放锁:lock.release()

4.递归锁:

与lock一样,支持嵌套,在多个锁没有释放时,一般会使用RLcok类。
Lock = treading.RLock()

5.信号量:

一次性允许线程的数量

6.事件:

用于多线程(如同信号灯)控制其他线程(如同车)的执行,事件是一个简单的线程同步对象。
set:把flag设为True
clear:把flag设为False
is_set:判断是否设置了flag
wait:会一直监听flag,如果没有检测到flag就一直处于阻塞状态

四.GIL:全局解释器锁:

在pyth设计之初为了数据安全,无论多少核,同时只能执行一个线程。

五.补充:多进程的实现

import multiprocessing
import time
import os
# multiprocessing模块(标准)提供了一个Process类,用来表示进程对象 ☆
def child_1(interval):
    print('1子进程%s开始执行,父进程是%s'%(os.getpid(),os.getppid()))
    start_time = time.time()
    time.sleep(interval)
    end_time = time.time()
    print('子进程%s结束执行,用时为%s'%(os.getpid(),end_time - start_time))

def child_2(interval):
    print('2子进程%s开始执行,父进程是%s'%(os.getpid(),os.getppid()))
    start_time = time.time()
    time.sleep(interval)
    end_time = time.time()
    print('子进程%s结束执行,用时为%s'%(os.getpid(),end_time - start_time))


if __name__ == '__main__':
    print('************************主进程开始******************************')
    print('主进程的pid时%s'%os.getpid())
    p1 = multiprocessing.Process(target=child_1,args=(2,))
    p2 = multiprocessing.Process(target=child_2,args=(2,))
    p1.start()
    p2.start()
    print('子进程1运行情况是:',p1.is_alive())
    print('子进程2运行情况是:',p2.is_alive())
    print('子进程1名字是',p1.name)
    print('子进程2名字是',p2.name)
    print('子进程1pid是',p1.pid)
    print('子进程2pid是',p2.pid)
    print('等待子进程结束')
    p1.join()
    p2.join()
    print('主进程pid是%s'%os.getpid())
    print('************************主进程结束******************************')

# 利用Process类的子类创建进程 ☆
# 通过定义一个类,使其继承Process类,每次实例化这个类的时候,就等同于实例化一个进程对象 ☆
# 注意:子类必须实现run方法(覆盖重写)
# 注意:子类必须调用父类的构造方法(用类型调用)
class SubProcess(multiprocessing.Process):
    def __init__(self,interval,name=''):
        multiprocessing.Process.__init__(self)
        self.interval  = interval
        if name:
            self.name = name
    def run(self):
        print('子进程%s开始,父进程是%s'%(os.getpid(),os.getppid()))
        start_time = time.time()
        time.sleep(self.interval)
        end_time = time.time()
        print('子进程%s结束,用时%s'%(os.getpid(),end_time-start_time))
if __name__ == '__main__':
    print('父进程%s开始'% os.getpid())
    p1 = SubProcess(1,'chile_01')
    p2 = SubProcess(1,'chile_02')
    p1.start()
    p2.start()
    print(p1.is_alive())
    print(p2.is_alive())
    print(p1.name,p1.pid)
    print(p2.name,p2.pid)
    p1.join()
    p2.join()
    print('父进程结束')



def task01():
    time.sleep(0.5)
    print('hello')
def task02():
    time.sleep(0.5)
    print('world')
if __name__ == '__main__':
    print('父进程%s开始'%os.getpid())
    p1 = multiprocessing.Process(target=task01)
    p2 = multiprocessing.Process(target=task02)
    p1.daemon = True
    p2.daemon = True
    p1.start()
    p2.start()
    time.sleep(1)
    print('父进程结束')

#上锁
def tack01(lock,f):
    with lock:
        n = 10
        while n>0:
            with open(f,'a+') as file:
                file.write('task01 hello world\n')
            n -=1
            print(111)
            time.sleep(0.2)
# 关于Lock锁:☆
# 应用场景:当多个进程需要访问共享资源的时候,Lock可以用来避免访问的冲突

def tack02(lock,f):
    with lock:
        n = 10
        while n>0:
            with open(f,'a+') as file:
                file.write('task02 hi python\n')
            n -=1
            print(222)
            time.sleep(0.2)
if __name__ == '__main__':
    lock = multiprocessing.Lock()
    f = 'demo.txt'
    p1 = multiprocessing.Process(target=tack01,args=(lock,f))
    p2 = multiprocessing.Process(target=tack02,args=(lock,f))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print('end')


#信号量
def worker(s):
    s.acquire()#获取
    print(str(os.getpid())+'acquire')
    time.sleep(1)
    print(str(os.getpid()) + 'release')
    s.release()#释放

if __name__ == '__main__':
    s = multiprocessing.Semaphore(3)        #规定信号量(一次能有几个进程)
    for i in range(1,7):
        multiprocessing.Process(target=worker,args=(s,)).start()
    print('end')
# 关于进程池Pool:
# 应用场景:如果需要创建几十个或上百个进程,就需要实例化更多的Process类或其子类
# 那么如何解决这个麻烦事呢?可以使用multiprocessing模块里的Pool类(进程池)
def ttask():
    print('子进程%s开始'%os.getpid())
    time.sleep(1)

if __name__ == '__main__':
    print('父进程%s开始'%os.getpid())
    pool = multiprocessing.Pool(3)
    for i in range(10):
        pool.apply_async(ttask)
        # pool.apply(ttask)
    pool.close()
    pool.join()
    print('父进程结束')


# 进程间的通信:
# 每个进程都有自己独立的地址空间、内存、数据栈以及其他记录运行状态的辅助数据 ☆
# 正常情况下,进程间是无法通信的:
num = 100
def fun1():
    print('子进程1开始')
    global num
    num+=50
    print(num)
    print('子进程1结束')
def fun2():
    print('子进程2开始')
    global num
    num-=50
    print(num)
    print('子进程2结束')
if __name__ == '__main__':
    print('父进程开始')
    print(num)
    p1 = multiprocessing.Process(target=fun1)
    p2 = multiprocessing.Process(target=fun2)
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print('父进程结束')
# 问题:那么如何进行进程间的通信呢?使用队列 ☆
# 关于队列:Queue ☆(multiprocessing模块里)
# 1)队列:就是模拟现实中的排队 ☆
# 2)队列的特点:先进先出 ☆
q = multiprocessing.Queue(3)
q.put('xiao1')
q.put('xiao2')
print(q.full())
q.put('xiao3')
print(q.full())
q.put('xiao4')#进入阻塞状态
q.put('xiao4',False)#只要满了就报异常
q.put('xiao4',True,2)#只要满了,等两秒,两秒后还是满的就报异常

try:
    q.put('xiao4',False)
except:
    print('队列已满')
if not q.empty():#如果队列不是空
    print('从队列中获取信息:')
    for i in range(q.qsize()):
        print(q.get())

# 使用队列实现进程间通信:☆
def w(q):
    if not q.full():
        for i in range(5):
            q.put('消息'+str(i))
            print('写入数据'+str(i))
def r(q):
    time.sleep(1)
    while not q.empty():
        print('读出'+q.get())
if __name__ == '__main__':
    q = multiprocessing.Queue(5)
    pw = multiprocessing.Process(target=w,args=(q,))
    pr = multiprocessing.Process(target=r,args=(q,))
    pw.start()
    pr.start()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值