day35

进程:生产者消费者模型

编程思想,模型,设计模式,理论等等,都是交给你一种编程的方法,以后你遇到类似的情况,套用即可

生产者消费者模型的三要素
  • 生产者:产生数据的
  • 消费者:接收数据做进一步处理的
  • 容器:盆(队列)

队列容器起到什么作用?

  • 起到缓冲的作用,平衡生产力与消费力,解耦
from multiprocessing import Process
from multiprocessing import Queue
import time
import random def producer(q, name):
for i in range(1,6):
time.sleep(random.randint(1, 2))
res = f"{i}号包子"
q.put(res)
print(f"生产者{name} 生产了{res}") def consumer(q, name):
while 1:
try:
food = q.get(timeout=3)
time.sleep(random.randint(1, 3))
print(f'\033[31;0m消费者{name} 吃了{food}\033[0m')
except Exception:
return if __name__ == '__main__':
q = Queue()
p1 = Process(target=producer, args=(q, "孙宇"))
p2 = Process(target=consumer, args=(q, "海狗")) p1.start()
p2.start()

线程的理论知识

什么是线程

一条流水线的工作流程

进程:在内存中开启一个进程空间,然后将主进程的所有资源数据复制一份,然后调用cpu去执行这些代码

之前的描述不够具体:

开启一个进程:在内存中开启一个进程空间,然后将主进程的所有的资源数据复制一份,然后调用线程去执行代码

进程是最小的资源单位,线程是最小的执行单位

以后你描述开启一个进程:

​ 开启一个进程:进程会在内存中开辟一个进程空间,将主进程的资料数据全部复制一份,线程会执行里面的代码

线程vs进程
  • 开启进程的开销非常大,比开启线程的开销大很多
  • 开启线程的速度非常快,要快几十倍到上百倍
  • 线程与线程之间可以共享数据,进程与进程之间需借助队列等方法实现通信
线程的应用

并发:一个cpu看起来像是同时执行多个任务

  • 单个进程开启三个线程,并发的执行任务

  • 开启三个进程并发的执行任务

    • 文本编辑器:

      1、输入文字

      2、在屏幕上显示

      3、保存在磁盘中

      开启多线程就非常好了:数据共享、开销小、速度快

线程没有地位之分,但是一个进程谁在干活?

只是我们自己的意思:我们把执行主程序的线程当作主线程

主线程在执行代码,当结束之后,你得等待其他线程结束之后,才能结束本进程

开启线程的两种方式

# 第一种方式
from threading import Thread
import time def task(name):
print(f"{name} is running")
time.sleep(1)
print(f"{name} is gone") if __name__ == '__main__':
t1 = Thread(target=task, args=("海狗",))
t1.start()
print("===主线程") # 线程是没有主次之分的 # 第二种方式
from threading import Thread
import time class MyThread(Thread):
def __init__(self, name, l1, s1):
super().__init__()
self.name = name
self.l1 = l1
self.s1 = s1 def run(self):
print(f"{self.name} is running")
time.sleep(1)
print(f"{self.name} is gone") if __name__ == '__main__':
t1 = MyThread("李业", [1,2,3], "180")
t1.start()
print("===主线程")

线程vs进程的代码对比

开启速度对比

多线程

from threading import Thread
import time def task():
print("hello") if __name__ == '__main__':
start_time = time.time()
# 在主进程下开启线程
t1 = Thread(target=task)
t2 = Thread(target=task)
t1.start()
t2.start()
print("主线程/主进程")
print(time.time() - start_time)
时间:0.0004723072052001953

多进程

from multiprocessing import Process
import time def work():
print("hellow") if __name__ == '__main__':
start_time = time.time()
# 在主进程下开启线程
p1 = Process(target=work)
p2 = Process(target=work)
p1.start()
p2.start()
print("主线程/主进程")
print(time.time() - start_time)
时间:0.023804903030395508
对比pid

进程

主进程和每个子进程的pid都不一样

from multiprocessing import Process
import os def task():
print(f"子进程:{os.getpid()}")
print(f"主进程:{os.getppid()}") if __name__ == '__main__':
p1 = Process(target=task) # 创建一个进程对象
p2 = Process(target=task) # 创建一个进程对象 p1.start()
p2.start()
print(f"==主{os.getpid()}")
结果:
==主12832
子进程:14176
主进程:12832
子进程:11756
主进程:12832

线程

只要是在一个进程内,主线程和每个线程都一样

from threading import Thread
import os def task():
print(os.getpid()) if __name__ == '__main__':
t1 = Thread(target=task)
t2 = Thread(target=task)
t1.start()
t2.start()
print(f"===主线程{os.getpid()}")
结果:
14480
14480
===主线程14480
同一个进程内线程共享内部数据
from threading import Thread
x = 3 def task():
global x
x = 100 if __name__ == '__main__':
t1 = Thread(target=task)
t1.start()
t1.join()
print(f"===主进程{x}")

线程的相关其他方法(了解)

from threading import Thread
from threading import activeCount
from threading import currentThread
from threading import enumerate
import os
import time # x = 3
def task():
# print(currentThread()) # 获取当前线程对象
# time.sleep(1)
print(333) if __name__ == '__main__':
t1 = Thread(target=task, name="线程1")
# t2 = Thread(target=task, name="线程2") t1.start()
# t1.setName("朱凡宇") # 添加name属性
# print(t1.getName()) # 查看name属性
# print(t1.name) # 查看name属性 ****
# print(t1.isAlive()) # 判断线程是否活着 # threading方法
# print(currentThread()) # 获取当前线程对象
# print(enumerate()) # 返回一个列表,包含所有的线程对象
print(activeCount()) # 返回存活线程的数量 ****
# t2.start()

join与守护进程(考点)

join:阻塞 告知主线程要等待我子线程执行完毕之后再执行下面的代码

from threading import Thread
import time def task(name):
print(f"{name} is running")
time.sleep(1)
print(f"{name} is gone") if __name__ == '__main__':
start_time = time.time()
t1 = Thread(target=task, args=("海狗1",))
t2 = Thread(target=task, args=("海狗2",))
t3 = Thread(target=task, args=("海狗3",)) t1.start()
t1.join()
t2.start()
t2.join()
t3.start()
t3.join()
print(f"===主线程{time.time() - start_time}")
结果:
海狗1 is running
海狗1 is gone
海狗2 is running
海狗2 is gone
海狗3 is running
海狗3 is gone
===主线程3.0027503967285156

守护进程

# 守护进程
from multiprocessing import Process
import time def foo():
print(123)
time.sleep(1)
print("end123") def bar():
print(456)
time.sleep(2)
print("end456") if __name__ == '__main__':
p1 = Process(target=foo)
p2 = Process(target=bar) p1.daemon = True
p1.start()
p2.start()
print("===主")
结果:
===主
456
end456

守护线程

守护线程:如果守护线程的生命周期小于其他线程,则他肯定结束,否则等待其他非守护线程和主线程结束之后结束

# 单线程
from threading import Thread
import time def sayhi(name):
# print("你滚!")
time.sleep(2)
print(f"{name} say hello") if __name__ == '__main__':
t = Thread(target=sayhi, args=("egon",))
t.daemon = True
t.start()
print("主线程")
结果:
主线程 # 多线程一
from threading import Thread
import time def foo():
print(123)
time.sleep(1)
print("end123") def bar():
print(456)
time.sleep(3)
print("end456") t1 = Thread(target=foo)
t2 = Thread(target=bar) t1.daemon = True
t1.start()
t2.start()
print("main------------")
结果:
123
456
main------------
end123
end456 # 多线程二
from threading import Thread
import time def foo():
print(123)
time.sleep(3)
print("end123") def bar():
print(456)
time.sleep(1)
print("end456") t1 = Thread(target=foo)
t2 = Thread(target=bar) t1.daemon = True
t1.start()
t2.start()
print("main------------")
结果:
123
456
main------------
end456

互斥锁(考点)

问题

from threading import Thread
import time
import random
x = 100 def task():
# time.sleep(random.randint(1, 2))
global x
temp = x
time.sleep(random.randint(1, 3))
x = temp -1 if __name__ == '__main__':
l1 = []
for i in range(100):
t = Thread(target=task)
l1.append(t)
t.start() for i in l1: # 使主线程无法先运行print(f"主线程{x}")
i.join()
print(f"主线程{x}")
结果: 一直是99

解决:

from threading import Thread
from threading import Lock
import time
import random
x = 100 def task(lock):
lock.acquire()
# time.sleep(random.randint(1, 2))
global x
temp = x
# time.sleep(random.randint(1, 3))
x = temp -1
lock.release() if __name__ == '__main__':
mutex = Lock()
l1 = []
for i in range(100):
t = Thread(target=task, args=(mutex,))
l1.append(t)
t.start() for i in l1: # 使主线程无法先运行print(f"主线程{x}")
i.join()
print(f"主线程{x}")
结果:一直是0

day35——生产者消费者模型、线程的更多相关文章

  1. 8.12 day31 进程间通信 Queue队列使用 生产者消费者模型 线程理论 创建及对象属性方法 线程互斥锁 守护线程

    进程补充 进程通信 要想实现进程间通信,可以用管道或者队列 队列比管道更好用(队列自带管道和锁) 管道和队列的共同特点:数据只有一份,取完就没了 无法重复获取用一份数据 队列特点:先进先出 堆栈特点: ...

  2. python并发编程-进程间通信-Queue队列使用-生产者消费者模型-线程理论-创建及对象属性方法-线程互斥锁-守护线程-02

    目录 进程补充 进程通信前言 Queue队列的基本使用 通过Queue队列实现进程间通信(IPC机制) 生产者消费者模型 以做包子买包子为例实现当包子卖完了停止消费行为 线程 什么是线程 为什么要有线 ...

  3. 生产者-消费者模型-线程安全队列Queue

    #python3 #product new data into the queue #comsume data from the queue from queue import Queue impor ...

  4. 4、网络并发编程--僵尸进程、孤儿进程、守护进程、互斥锁、消息队列、IPC机制、生产者消费者模型、线程理论与实操

    昨日内容回顾 操作系统发展史 1.穿孔卡片 CPU利用率极低 2.联机批处理系统 CPU效率有所提升 3.脱机批处理系统 CPU效率极大提升(现代计算机雏形) 多道技术(单核CPU) 串行:多个任务依 ...

  5. 第23章 java线程通信——生产者/消费者模型案例

    第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...

  6. python_way ,day11 线程,怎么写一个多线程?,队列,生产者消费者模型,线程锁,缓存(memcache,redis)

    python11 1.多线程原理 2.怎么写一个多线程? 3.队列 4.生产者消费者模型 5.线程锁 6.缓存 memcache redis 多线程原理 def f1(arg) print(arg) ...

  7. Python学习笔记——进阶篇【第九周】———线程、进程、协程篇(队列Queue和生产者消费者模型)

    Python之路,进程.线程.协程篇 本节内容 进程.与线程区别 cpu运行原理 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Ev ...

  8. Java多线程之~~~使用Exchanger在线程之间交换数据[这个结合多线程并行会有解决很多问题]生产者消费者模型

    http://blog.csdn.net/a352193394/article/details/39503857  Java多线程之~~~使用Exchanger在线程之间交换数据[这个结合多线程并行会 ...

  9. 进程,线程,GIL,Python多线程,生产者消费者模型都是什么鬼

    1. 操作系统基本知识,进程,线程 CPU是计算机的核心,承担了所有的计算任务: 操作系统是计算机的管理者,它负责任务的调度.资源的分配和管理,统领整个计算机硬件:那么操作系统是如何进行任务调度的呢? ...

随机推荐

  1. Java Web 项目的文件/文件夹上传下载

    需求: 支持大文件批量上传(20G)和下载,同时需要保证上传期间用户电脑不出现卡死等体验: 内网百兆网络上传速度为12MB/S 服务器内存占用低 支持文件夹上传,文件夹中的文件数量达到1万个以上,且包 ...

  2. 浏览器事件循环 & nodejs事件循环

    第1篇:如何理解EventLoop——宏任务和微任务篇 宏任务(MacroTask)引入 在 JS 中,大部分的任务都是在主线程上执行,常见的任务有: 渲染事件 用户交互事件 js脚本执行 网络请求. ...

  3. 75: libreoj #10028 双向宽搜

    $des$ 实现一个bfs $sol$ 写了一个双向bfs #include <bits/stdc++.h> using namespace std; #define Rep(i, a, ...

  4. Vue.set 向响应式对象中添加响应式属性,及设置数组元素触发视图更新

    一.为什么需要使用Vue.set? vue中不能检测到数组和对象的两种变化: 1.数组长度的变化 vm.arr.length = 4 2.数组通过索引值修改内容 vm.arr[1] = ‘aa’ Vu ...

  5. 可分离卷积详解及计算量 Basic Introduction to Separable Convolutions

    任何看过MobileNet架构的人都会遇到可分离卷积(separable convolutions)这个概念.但什么是“可分离卷积”,它与标准的卷积又有什么区别?可分离卷积主要有两种类型: 空间可分离 ...

  6. rust所有权

    所有权与函数 fn main() { let s = String::from("hello"); takes_ownership(s); //s的值移动到函数里 let x = ...

  7. compile install deploy;

    如果compile的话,也会打包在target里面: 如果有问题的话就找到本地仓库把它删掉: /Users/yinfuqing/.m2/repository/com/sankuai/qcs/qcs-r ...

  8. [C++] 对象指针使用方法

    对象指针:指向类对象的指针 类指针指向类变量(对象)的地址 对象指针定义格式: 类类型 *变量名: 举例: #include <iostream> using namespace std; ...

  9. [转]Windows内存堆内容整理总结

    在系统安全研究中,堆,是一个极其重要的内存区域以及研究的热点.堆,区别于栈区.全局数据区以及代码区,它的主要作用是允许程序在运行时动态地申请某个大小的内存空间.本文将从宏观到微观,简单梳理总结一下Wi ...

  10. 第2课第7节_Java面向对象编程_内部类_P【学习笔记】

    摘要:韦东山android视频学习笔记  1.什么是内部类:在类的内部定义一个类,内部类可以访问类的私有属性 class Outer{ ; class Inner{ public void print ...