首页 > 其他分享 >第四十七天 线程的相关知识

第四十七天 线程的相关知识

时间:2023-06-08 12:11:05浏览次数:21  
标签:__ Process get 队列 知识 print 第四十七 线程 进程

一、昨日内容回顾

如何创建进程
"""进程也可以理解成是内存中某一块存储空间"""
# 针对不同的操作系统代码创建进程的原理有区别
windows以模块导入的方式
linux\mac以拷贝的方式

join方法
主进程代码等待子进程代码运行结束之后再往后执行
p.join()

进程间数据隔离
在同一台计算机上的多个应用程序在内存中是相互隔离的(物理级别隔离)

进程对象属性和方法
1.获取进程号
current_process().pid
os.getpid()
os.getppid()
2.杀死子进程
terminate()
3.判断进程是否存活
is_alive()

僵尸进程与孤儿进程
僵尸进程
进程结束之后不会立刻清空所有信息,会短时间保留进程号等信息等待父进程回收,所有的进程都会经历僵尸进程
父进程回收子进程资源的两种方式
1.父进程正常结束
2.调用join方法
孤儿进程
子进程正常运行 父进程意外死亡(主动杀死>>> taskkill\kill)

守护进程
守护进程会随着主进程的结束立刻结束
p.daemon = True  # 将子进程设置为守护进程:主进程结束 子进程立刻结束
p.start()

互斥锁
"""
并发的情况下操作同一份数据 极有可能造成数据错乱的问题
这个时候统一都会采用互斥锁的策略来解决(无论是基础阶段还是后期)

互斥锁:将并发变成串行 牺牲了效率但是保证了数据的安全

以后正常编程很少会出现让我们自己编写代码操作锁的情况!!!
"""
mutex = Lock()
mutex.acquire()  # 抢锁互斥锁
mutex.release()  # 放锁

二、消息队列

# 由于目前的知识储备还不够直接学习消息队列 所以先学习内置队列
"""
队列:先进先出(使用频率很高)
堆栈:先进后出(特定常见下用)
"""
# 以后我们会直接使用别人封装好的消息队列 实现各种数据传输
from multiprocessing import Queue

q = Queue(5)  # 自定义队列的长度
q.put(111)
q.put(222)
q.put(333)
print(q.full())  # False  判断队列是否满了
q.put(444)
q.put(555)
print(q.full())  # True
# q.put(666)  # 超出最大长度 原地阻塞等待队列中出现空位
# 程序在阻塞的过程中就会卡住一直执行
print(q.get())
print(q.get())
print(q.empty())  # False  判断队列是否空了
print(q.get())
print(q.get())
print(q.get())
print(q.empty())  # True
# print(q.get())  # 队列中没有值 继续获取则阻塞等待队列中给值
print(q.get_nowait())  # 队列中如果没有值 直接报错
"""
full()
empty()
get_nowait()
上述方法能否在并发的场景下精准使用???
不能用,因为当有多个进程操作队列里面的数据的时候,full(),empty()等方法就有可能刚好失效!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
之所以介绍队列是因为它可以支持进程间数据通信
get()将队列的值取出来了之后再put数据就不会卡住
但是当put的数据数量超过范围get()是不能解决卡住的问题的
"""
# 队列的最大作用就是使得原来数据隔离的进程之间实现数据交互

三、IPC机制(进程间通信)

"""
1.主进程与子进程数据交互
2.两个子进程数据交互
本质:不同内存空间中的进程数据交互
就是专门有个空间拿来存数据和被读取
"""
from multiprocessing import Queue, Process

def producer(q):
    # print('子进程producer从队列中取值>>>:', q.get())
    q.put('子进程producer往队列中添加值')
def consumer(q):
    print('子进程consumer从队列中取值>>>:', q.get())
if __name__ == '__main__':
    q = Queue()
    p = Process(target=producer, args=(q,))
    p1 = Process(target=consumer, args=(q,))
    p.start()
    p1.start()
    print('主进程')
# 没啥好说的,创建两个子进程,一个生产者,一个消费者

四、生产者消费者模型

# 生产者
	负责生产/制作数据
# 消费者
	负责消费/处理数据
"""
比如在爬虫领域中
	会先通过代码爬取网页数据(爬取网页的代码就可以称之为是生产者)
	之后针对网页数据做筛选处理(处理网页的代码就可以称之为消费者)
如果使用进程来演示
	除了有至少两个进程之外 还需要一个媒介(消息队列)
以后遇到该模型需要考虑的问题其实就是供需平衡的问题
	生产力与消费力要均衡
"""
from multiprocessing import Process, Queue, JoinableQueue
import time
import random


def producer(name, food, q):
    for i in range(10):
        data = f'{name}生产了{food}{i}'
        print(data)
        time.sleep(random.randint(1, 3))  # 模拟产生过程
        q.put(data)


def consumer(name, q):
    while True:
        food = q.get()
        time.sleep(random.random())
        print(f'{name}吃了{food}')


if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=producer, args=('大厨jason', '韭菜炒蛋', q))
    p2 = Process(target=producer, args=('学徒tony', '狗不理', q))
    p3 = Process(target=producer, args=('老板kevin', '秘制小汉堡', q))
    c1 = Process(target=consumer, args=('涛涛', q))
    c2 = Process(target=consumer, args=('龙龙', q))
    p1.start()
    p2.start()
    p3.start()
    c1.start()
    c2.start()
    print('主进程')
"""
1.你会发现程序跑到后面会卡住,生产环节的生产食物是有数量上限的,但是程序没跑完
2.生产者代码没到上限卡不住的,是因为消费卡在q.get()这里了,因为拿不到数据
3.不能在子进程中使用q.empty(),因为有多个子进程,一旦队列第一个被吃掉了,子进程就会直接结束
"""
import pickle
from multiprocessing import Process, Queue, JoinableQueue
import time
import random


def producer(name, food, q):
    for i in range(10):
        data = f'{name}生产了{food}{i}'
        print(data)
        time.sleep(random.randint(1, 3))  # 模拟产生过程
        q.put(data)


def consumer(name, q):
    while True:
        food = q.get()
        if food == None:
            print('完蛋了 没得吃了 要饿死人了')
            break
        time.sleep(random.random())
        print(f'{name}吃了{food}')


if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=producer, args=('大厨jason', '韭菜炒蛋', q))
    p2 = Process(target=producer, args=('学徒tony', '狗不理', q))
    c1 = Process(target=consumer, args=('涛涛', q))
    c2 = Process(target=consumer, args=('龙龙', q))
    p1.start()
    p2.start()
    c1.start()
    c2.start()
    p1.join()
    p2.join()
    q.put(None)
    q.put(None)
"""
1.解决思路是利用利用join使得在生产完成之后在队列的结尾放上None
2.加上判断使得在迟到None的时候循环直接结束不再执行q.get()
3.但是只有一个None,有两个人要来拿,这个时候就需要有几个人就有几个None
4.这就很麻烦了结束标志需要与消费者数量一致
5.对列中已经自己加了锁,所以多进程不会冲突
"""
from multiprocessing import Process, Queue, JoinableQueue
import time
import random


def producer(name, food, q):
    for i in range(5):
        data = f'{name}生产了{food}{i}'
        print(data)
        time.sleep(random.randint(1, 3))  # 模拟产生过程
        q.put(data)


def consumer(name, q):
    while True:
        food = q.get()
        # if food == None:
        #     print('完蛋了 没得吃了 要饿死人了')
        #     break
        time.sleep(random.random())
        print(f'{name}吃了{food}')
        q.task_done()  # 每次取完数据必须给队列一个反馈


if __name__ == '__main__':
    # q = Queue()
    q = JoinableQueue()
    p1 = Process(target=producer, args=('大厨jason', '韭菜炒蛋', q))
    p2 = Process(target=producer, args=('老板kevin', '秘制小汉堡', q))
    c1 = Process(target=consumer, args=('涛涛', q))
    c2 = Process(target=consumer, args=('龙龙', q))
    c1.daemon = True
    c2.daemon = True
    p1.start()
    p2.start()
    c1.start()
    c2.start()
    # 生产者生产完所有数据之后 往队列中添加结束的信号
    p1.join()
    p2.join()
    # q.put(None)  # 结束信号的个数要跟消费者个数一致才可以
    # q.put(None)
    """队列中其实已经自己加了锁 所以多进程取值也不会冲突 并且取走了就没了"""
    q.join()  # 等待队列中数据全部被取出(一定要让生产者全部结束才能判断正确)
    """执行完上述的join方法表示消费者也已经消费完数据了"""
"""
1.使用q = JoinableQueue()为生产的数据进行计数
2.q.task_done()  # 每次取完数据必须给队列一个反馈取一次上面的计数就减少一次
3.q.join()前面必须带着p1.join(),p2.join()因为在生产结束之后才能知道有多少个,才能确定队列中的数据在q.task_done()之后有没有被吃完
4.c1.daemon = True,c2.daemon = True的作用是将吃作为守护进程一旦计数结束就直接不吃了
"""

标签:__,Process,get,队列,知识,print,第四十七,线程,进程
From: https://www.cnblogs.com/tuq2791/p/17465830.html

相关文章

  • FreeSwitch基础知识(一)
        总的来说,FreeSwitch由一个稳定的核心(Core)及一些外围模块组成、这些外围模块根据其功能和用途的不同又分为Endpoint、Codec、Application等不同的类别。    FreeSwitch内部使用线程模型来处理并发请求,每个连接都在单独的线程中进行处理,不同的线程间通过Mutex互......
  • 嵌入式相关知识点概念笔记
    01操作系统(OperatingSystem,OS)是管理计算机硬件与软件资源的系统软件,同时也是计算机系统的内核与基石。操作系统需要处理管理与配置内存、决定系统资源供需的优先次序、控制输入与输出设备、操作网络与管理文件系统等基本事务。操作系统也提供一个让用户与系统交互的操作界面。......
  • 4. 数学知识(I)
    4.1质数4.1.1试除法判定质数模板:AcWing866.试除法判定质数题目:给你\(n\)个正整数\(a_i\),判断其是否是质数。\(1\len\le100,1\lea_i\le2^{31}-1\)。思路:根据质数的定义,可知若\(2\sima-1\)之间的数都不能整除\(a\),则\(a\)为质数。那么遍历\(2\sima-1\)之间......
  • 多线程中的上下文切换
    我们都知道,在并发编程中,并不是线程越多就效率越高,线程数太少可能导致资源不能充分利用,线程数太多可能导致竞争资源激烈,然后上下文切换频繁造成系统的额外开销。大量的超时报警,通过工具分析,cs指标很高,然后分析日志,发现有大量wait()相关的Exception,这个时候我们怀疑是在多线程并发处......
  • 软测5班数据库基础知识
    函数:字符串函数charindex('查找内容','源字符串'[,起始位置]),返回值为查找到的内容首字母所在的位置,如果未找到返回0。len('字符串'),返回字符串长度。lower('字符串'),返回小写字母。upper('字符串'),返回大写字母。ltrim('字符串'),返回去除字符串左边空格。rtrim('字符串'),返......
  • 关于Java中多线程
    基本概念什么是进程-->是操作系统资源分配和调度的最小(基本)单位(操作系统分配给当前进程一个内存区域供其使用)什么是线程-->是程序运行的基本单位(等待操作系统分配时间片让CPU执行该内存区域中的代码)进程和线程的关系-->一个进程可以存在多个线程线程是由进程创建的(寄......
  • BMS系列知识点
    一、电流采集主流的电流采集方案有两种:一种是基于串联电阻的电流监测,采用最基本的电压电流关系来进行测量;另一种是基于电流传感器的电流监测,而传感器还分为普通的开环式霍尔传感器和磁通门电流传感器。1.1基于SHUNT的电流测量原理:电压量是最直接能够被测量到的,因此将电流信号......
  • 异步调用方法并弹出处理中窗体(转载)---线程池的封装
    原文链接:[C#]非同步呼叫方法並跳出處理中視窗|愛流浪的小風-點部落(dotblogs.com.tw)前言 當我們在Winform進行某些比較花時間的運算時,若沒有使用非同步的方法來呼叫,畫面上的視窗就會顯示沒有回應,這是一種比較差的使用者體驗,可能會讓使用者以為當機了,在這邊為了方便......
  • TypeScript 的基础知识(跟着ChartGpt学习)
    以下都是我的ChartGpt老师教学的内容哦,(若想知道怎么用ChartGpt学习,或者想知道我的问答方式,可以点这个查看我的学习记录)一:TypeScript的基本数据类型TypeScript支持JavaScript的基本数据类型,包括number、string、boolean、null、undefined和symbol。其中,number表示数......
  • 线程同步:Lock锁
        ......