第一阶段:Python开发基础 day39 多线程的进阶补充内容

昨日回顾

'''
cpu最小的执行单位:线程

进程 资源集合
线程 执行单位

操作系统 --> 工厂
进程     --> 车间
线程(cpu)--> 流水线(电源)


进程的内存空间彼此隔离
线程共享同一份资源
'''
### 方式一
# from threading import Thread
#
# def task():
#     pass
#
# # if __name__ == '__main__':
# t = Thread(target= task)
# t.start()

### 方式二 类
# pass

#### 创建速度
# 进程需要申请内存空间 慢
# 线程相当于直接告诉操作系统去干个什么活.  快


### 线程共享资源

### 线程的join方法: 等待被join的线程结束
    # 进程的join:等待被join的进程结束
### 线程其他的相关用法: getname setname enumerate() currentThread

### 守护线程: 守护的是进程运行周期

一、线程锁

from threading import Thread,Lock

x = 0
mutex = Lock()
def task():
    global x
    # mutex.acquire()
    for i in range(200000):
        x = x+1
        # t1 的 x刚拿到0 保存状态 就被切了
        # t2 的 x拿到0 进行+1       1
        # t1 又获得运行了  x = 0  +1  1
        # 思考:一共加了几次1? 加了两次1 真实运算出来的数字本来应该+2 实际只+1
        # 这就产生了数据安全问题.
    # mutex.release()

if __name__ == '__main__':
    t1 = Thread(target=task)
    t2 = Thread(target=task)
    t3 = Thread(target=task)
    t1.start()
    t2.start()
    t3.start()

    t1.join()
    t2.join()
    t3.join()
    print(x)

二、死锁问题

from threading import Thread,Lock
mutex1 = Lock()
mutex2 = Lock()
import time
class MyThreada(Thread):
    def run(self):
        self.task1()
        self.task2()
    def task1(self):
        mutex1.acquire()
        print(f'{self.name} 抢到了 锁1 ')
        mutex2.acquire()
        print(f'{self.name} 抢到了 锁2 ')
        mutex2.release()
        print(f'{self.name} 释放了 锁2 ')
        mutex1.release()
        print(f'{self.name} 释放了 锁1 ')

    def task2(self):
        mutex2.acquire()
        print(f'{self.name} 抢到了 锁2 ')
        time.sleep(1)
        mutex1.acquire()
        print(f'{self.name} 抢到了 锁1 ')
        mutex1.release()
        print(f'{self.name} 释放了 锁1 ')
        mutex2.release()
        print(f'{self.name} 释放了 锁2 ')


for i in range(3):
    t = MyThreada()
    t.start()

# 两个线程
# 线程1拿到了(锁头2)想要往下执行需要(锁头1),
# 线程2拿到了(锁头1)想要往下执行需要(锁头2)
# 互相都拿到了彼此想要往下执行的必需条件,互相都不放手里的锁头.

三、递归锁(了解)

from threading import Thread,Lock,RLock
# 递归锁 在同一个线程内可以被多次acquire
# 如何释放 内部相当于维护了一个计数器 也就是说同一个线程 acquire了几次就要release几次
# mutex1 = Lock()
# mutex2 = Lock()
mutex1 = RLock()
mutex2 = mutex1

import time
class MyThreada(Thread):
    def run(self):
        self.task1()
        self.task2()
    def task1(self):
        mutex1.acquire()
        print(f'{self.name} 抢到了 锁1 ')
        mutex2.acquire()
        print(f'{self.name} 抢到了 锁2 ')
        mutex2.release()
        print(f'{self.name} 释放了 锁2 ')
        mutex1.release()
        print(f'{self.name} 释放了 锁1 ')

    def task2(self):
        mutex2.acquire()
        print(f'{self.name} 抢到了 锁2 ')
        time.sleep(1)
        mutex1.acquire()
        print(f'{self.name} 抢到了 锁1 ')
        mutex1.release()
        print(f'{self.name} 释放了 锁1 ')
        mutex2.release()
        print(f'{self.name} 释放了 锁2 ')


for i in range(3):
    t = MyThreada()
    t.start()

四、信号量

from threading import Thread,currentThread,Semaphore
import time

def task():
    sm.acquire()
    print(f'{currentThread().name} 在执行')
    time.sleep(3)
    sm.release()

sm = Semaphore(5)
for i in range(15):
    t = Thread(target=task)
    t.start()

五、GIL

# 在Cpython解释器中有一把GIL锁(全局解释器锁),GIl锁本质是一把互斥锁。
# 导致了同一个进程下,同一时间只能运行一个线程,无法利用多核优势.
# 同一个进程下多个线程只能实现并发不能实现并行.

# 为什么要有GIL?
# 因为cpython自带的垃圾回收机制不是线程安全的,所以要有GIL锁.

# 导致了同一个进程下,同一时间只能运行一个线程,无法利用多核优势.
#
#分析:
# 我们有四个任务需要处理,处理方式肯定是要玩出并发的效果,解决方案可以是:
# 方案一:开启四个进程
# 方案二:一个进程下,开启四个线程

# 计算密集型 推荐使用多进程
#  每个都要计算10s
#  多线程
#  在同一时刻只有一个线程会被执行,也就意味着每个10s都不能省,分开每个都要计算10s,共40.ns
#  多进程
#  可以并行的执行多个线程,10s+开启进程的时间

# io密集型 推荐多线程
# 4个任务每个任务90%大部分时间都在io.
# 每个任务io10s 0.5s
# 多线程
# 可以实现并发,每个线程io的时间不咋占用cpu, 10s + 4个任务的计算时间
# 多进程
# 可以实现并行,10s+1个任务执行的时间+开进程的时间

六、多进程vs多线程

from threading import Thread
from multiprocessing import Process
import time

# 计算密集型
# def work1():
#     res=0
#     for i in range(100000000): #1+8个0
#         res*=i
#
# if __name__ == '__main__':
#     t_list = []
#     start = time.time()
#     for i in range(4):
#         # t = Thread(target=work1)
#         t = Process(target=work1)
#         t_list.append(t)
#         t.start()
#     for t in t_list:
#         t.join()
#     end = time.time()
#     # print('多线程',end-start) # 多线程 15.413789510726929
#     print('多进程',end-start) # 多进程 4.711405515670776


# # io密集型
# def work1():
#     x = 1+1
#     time.sleep(5)
#
#
# if __name__ == '__main__':
#     t_list = []
#     start = time.time()
#     for i in range(4):
#         t = Thread(target=work1)
#         # t = Process(target=work1)
#         t_list.append(t)
#         t.start()
#     for t in t_list:
#         t.join()
#     end = time.time()
#     print('多线程',end-start) #  多线程 5.002625942230225
#     # print('多进程',end-start) # 多进程 5.660863399505615
posted @ 2019-09-18 15:40  foreversun92  阅读(152)  评论(0编辑  收藏  举报