python-day36_ 线程 多线程 守护线程 线程互斥锁 线程的并发 joinablequeue

1 joinablequeue

from multiprocessing import JoinableQueue
#  join  是等待某个任务运行完毕  able是可以的意思 Queue是队列   综合起来  就是一个可以被join的队列  继承自Queue

j = JoinableQueue()
# j.put('123') # 放入信息
# print(j.get()) # 获取信息
# j.task_done()   # 告知队列这次数据取完了  不是表示任务全部处理完成  而是 取出来某个数据处理完成

j.put('wsx')
j.put('222')
j.put('333')
print('取走了%s'% j.get())
j.task_done()
j.task_done()
# j.task_done()
j.join()  #  只有取完了  才可以继续进行   没取完则一直等

# :结论  task_done() 和.put()次数要对应起来  即放入几次数据要有几次告知信息

案例

from multiprocessing  import Process,JoinableQueue
import time,random

def make_hot_dog(name,q):
    for i in range(5):
        time.sleep(random.randint(1,3))
        print('%s正在生产%s个热狗'%(name,i) )
        q.put('%s的%s热狗'%(name,i))  # 放入容器


def eat_hot_dog(name,q):
    while True:
        hot_dog= q.get() # 取出容器内容
        time.sleep(random.randint(1, 3))
        print('%s吃掉了%s'% (name,hot_dog))
        q.task_done()  # 告知取出了数据



if __name__ == '__main__':
    q=JoinableQueue()  #  建立队列
    p1 = Process(target=make_hot_dog,args=('owen的热狗店',q))
    p2 = Process(target=make_hot_dog,args=('jerry的热狗店',q))
    p3 = Process(target=make_hot_dog,args=('take的热狗店',q))

    c1 = Process(target=eat_hot_dog,args=('思聪',q))
    c1.daemon = True  # 守护进程

    c2 = Process(target=eat_hot_dog,args=('蔡徐坤',q))
    c2.daemon = True


    p1.start()
    p2.start()
    p3.start()

    c1.start()
    c2.start()


    p1.join()  # 保证子进程先于主线程运行
    print('第一家生产完毕')

    p2.join()
    print('第二家生产完毕')

    p3.join()  
    print('第san家生产完毕')



    c1.join()
    print('热狗吃完了')
    c2.join()
    print('热狗吃完了')

2 线程

2.1什么是线程:

线程是操作系统最小运算调度单位 ,线程被包裹在进程当中 ,线程指的就是固定的执行流程

2.2 线程和进程的关系

1 线程:  是一个正在运行的程序, 是操作系统将数据加载到内存中去运行,那么进程就产生了,那么可以理解进程是是一个资源单位,其包含运行程序所需要的所有资源.

2 进程:是操作系统最小运算调度单位,是被包含在进程当中的 ,任务都是由线程执行的,

3:线程是依附进程存活的,没有线程,进程的资源是无法被调动执行的 ,所以一个进程至少包含一个线程,那这个线程也称之为主线程.(主线程是由操作系统启动一个程序时,就自动会为其创建一个主线程)

4:线程也可以由程序后期取开启 ,这时开启的线程叫做子线程

2.3 为毛需要多线程

目的:为了提高效率  (多线程处理数据比单个线程处理速度要快的多)

3 如何使用线程

主要语法和进程一样

区别在进程开启子进程方法必须在main下面.    线程可以任意位置开启  因为内存中的进程时相互隔离的 必须加以判断   而线程是在进程当中的  数据可以共享的 

3.1线程两种创建方式

## 2 线程

### 2.1什么是线程:

线程是操作系统最小运算调度单位 ,线程被包裹在进程当中 ,线程指的就是固定的执行流程

### 2.2 线程和进程的关系

1 线程:  是一个正在运行的程序, 是操作系统将数据加载到内存中去运行,那么进程就产生了,那么可以理解进程是是一个资源单位,其包含运行程序所需要的所有资源. 

2 进程:是操作系统最小运算调度单位,是被包含在进程当中的 ,任务都是由线程执行的,

3:线程是依附进程存活的,没有线程,进程的资源是无法被调动执行的 ,所以一个进程至少包含一个线程,那这个线程也称之为主线程.(主线程是由操作系统启动一个程序时,就自动会为其创建一个主线程)

4:线程也可以由程序后期取开启 ,这时开启的线程叫做子线程

### 2.3 为毛需要多线程

目的:为了提高效率  (多线程处理数据比单个线程处理速度要快的多)

## 3 如何使用线程

主要语法和进程一样

区别在进程开启子进程方法必须在main下面.    线程可以任意位置开启  因为内存中的进程时相互隔离的 必须加以判断   而线程是在进程当中的  数据可以共享的  

### 3.1线程两种创建方式

3.2 线程的特点

1:线程开启的资源占用小  (与开进程做对比)

2:同一程序中   线程之间数据是共享的 

3: 线程之间没有父子之分,等级是平等的 所有线程pip都是一样的

验证案例

1:线程开启的资源占用小  (与开进程做对比)
开启100进程和100个线程  看运算时间  做对比  线程所需时间远远小于开进程
    
    
from multiprocessing import Process
from threading import Thread
import time


def task():
    pass

if __name__ == '__main__':
    t_time = time.time()
    for i in range(100):
        # p=Process(target=task)
        p = Thread(target=task)
        p.start()


    print(time.time()-t_time)
# 2:同一程序中   线程之间数据是共享的

from threading import Thread

a = 10
def task():
    global a
    a=20
    print('子线程running')
    print(a)


t=Thread(target=task)
t.start()
print('主线程running')

print(a)

# 子线程runing
# 20
# 主线程runing
# 20
3: 线程之间没有父子之分,等级是平等的 所有线程pip都是一样的
import
os from threading import Thread def task(): pass for i in range(5): t= Thread(target=task) t.start() print(os.getpid()) # 打印的结果都一样


4 守护线程  了解   t.daemon  = Ture

一个线程可以守护另外一个线程  当被守护线程结束  自己也随之结束

import random
import time
from threading import Thread


def task():
    print('子线程running!')
    time.sleep(5)
    print('子线程over!')

if __name__ == '__main__':

    t= Thread(target=task)
    t.daemon = True  
    # 设置守护进程  现在子线程守护主线程  当主线程挂了  子线程就不在运行了  所以主线程over之后子线程('子线程over!')这句就不走了
    t.start()
    print('主线程running!' )
    time.sleep(random.randint(1,3))
    print('主线程over!')


#  运行结果
#子线程running!
# 主线程running!
# 主线程over!


#  注意点  此题中如果还有其他子线程  且没有进行守护 那么主线程要等到那个子线程结束才能结束  此时守护的那个子线程再算结束  

5 线程安全问题 ==>线程互斥锁

因为线程之间数据是共享的   数据共享意味着可以多个线程操作同一个资源 那么就有可能导致数据的一个错乱  那么这时就导入线程互斥锁的  和进程的进程互斥锁类似

# 通过10次子线程将10 变成0  那么就有多个子线程操作同一个资源  防止错乱 就得加上锁  那么主线程也得先让子线程运行完采取执行 需要join
import time
from threading import Thread,Lock,enumerate
look= Lock()  # 建锁
num = 10
def task():
    global num
    look.acquire()
    a = num
    time.sleep(0.1)
    num = a-1
    look.release()


for i in range(10):
    t = Thread(target=task)
    t.start()
# print(enumerate())   会显示所有线程名称  
for t in enumerate()[1:]:  #  返回当前活动的所有Thread对象的列表。  
    t.join()

print(num)

6 死锁 问题

"""
    死锁问题
    当程序出现了不止一把锁,分别被不同的线程持有, 有一个资源要想使用必须同时具备两把锁
    这时候程序就会进程无限卡死状态 ,这就称之为死锁
    例如:
        要吃饭 必须具备盘子和筷子   但是一个人拿着盘子 等筷子  另一个人拿着筷子等盘子


    如何避免死锁问题
        锁不要有多个,一个足够
        如果真的发生了死锁问题,必须迫使一方先交出锁

"""
import time
from threading import Thread,Lock,current_thread


# 盘子
lock1 = Lock()

# 筷子
lock2  = Lock()

def eat1():
    lock1.acquire()
    print('%s抢到了盘子' % current_thread().name)
    lock1.acquire()

    time.sleep(0.5)

    lock2.acquire()
    print('%s抢到了筷子' % current_thread().name)
    lock2.release()

    time.sleep(0.5)

    print('%s开吃了' % current_thread().name)
    time.sleep(0.5)


    print('%s放下了筷子' % current_thread().name)
    time.sleep(0.5)

    print('%s放下了盘子' % current_thread().name)


def eat2():
    lock2.acquire()
    print('%s抢到了筷子' % current_thread().name)
    lock2.release()

    time.sleep(0.5)

    lock1.acquire()
    print('%s抢到了盘子' % current_thread().name)
    lock1.release()

    time.sleep(0.5)

    print('%s开吃了' % current_thread().name)
    time.sleep(0.5)

    print('%s放下了盘子' % current_thread().name)
    time.sleep(0.5)

    print('%s放下了筷子' % current_thread().name)



t1 = Thread(target=eat1)
t2 = Thread(target=eat2)

t1.start()
t2.start()



# 这就出现了死锁问题  
# Thread-1抢到了盘子
# Thread-2抢到了筷子 之后等着进行 没有退出

7 Rlock

"""
    Rlock  了解
        称之为递归锁
        或者可重入锁
    Rlock不使用用来解决死锁问题的

    与Lock唯一的区别:
    Rlock同一线程可以多次执行acquire 但是执行几次acquire就应该对应release几次

    如果一个线程已经执行过acquire 其他线程将无法执行acquire

"""
from threading import RLock, Lock, Thread

# l = Lock()
#
# l.acquire()
# print("1")
# l.acquire()
# print("2")


l = RLock()

# l.acquire()
# print("1")
# l.acquire()
# print("2")

def task():
    l.acquire()
    print("子run......")
    l.release()


# 主线程锁了一次
l.acquire()
l.acquire()

l.release()
l.release()
t1 = Thread(target=task)
t1.start()

8 信号量

"""
 信号量 了解


可以现在被锁定的代码 同时可以被多少线程并发访问
Lock 锁住一个马桶  同时只能有一个
Semaphore 锁住一个公共厕所    同时可以来一堆人


用途: 仅用于控制并发访问   并不能防止并发修改造成的问题
"""

from threading import Semaphore, Thread
import time

s = Semaphore(5)
def task():
    s.acquire()
    print("子run")
    time.sleep(3)
    print("子over")
    s.release()

for i in range(10):
    t = Thread(target=task)
    t.start()

猜你喜欢

转载自www.cnblogs.com/wakee/p/10976648.html