并发编程,python的进程,与线程
并发编程
操作系统发展史
基于单核研究
多道技术
1.空间上的复用
多个程序公用一套计算机硬件
2.时间上的复用
切换+保存状态
例子:洗衣 烧水 做饭
切换
1.程序遇到IO操作系统会立刻剥夺走CPU的执行权限
IO:input,sleep,accept,recv...阻塞 日常生活中使用软件通常都是IO密集型
2.当你的程序长时间占用CPU的时候也会被操作系统剥夺走cpu的执行权限
进程理论
进程调度
时间片轮转法+多级反馈队列
进程三状态图
ps:程序不会立刻进入运行态 都会现在就绪态等待cpu的执行
同步异步:指的是任务的提交方式
同步:提交任务之后原地等待任务的返回结果 期间不做任何事
异步:提交任务之后立刻执行下一行代码 不等待任务的返回结果 >>> 结果的获取使用异步回调机制
阻塞非阻塞:指的是程序的运行状态
阻塞:阻塞态
非阻塞:就绪态或者是运行态
创建进程的两种方式
使用使用Process实例化
继承Process类重写run方法
ps:windows在开启进程的时候必须在__main__代码块内,因为windows是以模块导入的方式从上执行代码
什么是进程:
正在运行的程序
一个进程对应到内存中就是一块独立的内存空间
join方法
主进程等待某个指定的子进程运行结束,不影响其他子进程的运行
进程对象及其他方法
current_process().pid
os.getpid
os.getppid
terminate()
is_alive()
守护进程
daemon
这一句化必须在start之前使用
进程间数据是隔离的
互斥锁
多个程序操作用一份数据的时候会出现数据错乱的现象
如何避免:
将操作数据的部分加锁处理
会将并发变成串行牺牲了效率但是保证了数据的安全
抢锁
acquire()
释放锁
release()
抢锁步骤是由操作系统决定的,即到底谁将会被分配到锁,进而可以被执行.
只有当程序释放了锁,之后的程序才能继续去抢锁.
进程间通信IPC机制
一般进程间通信会使用队列这一数据类型来进行数据通信.
ps:
"""
队列:先进先出
堆栈:先进后出
"""
示例:
from multiprocessing import Queue
q = Queue(5) # 括号内可以传参数 表示的是这个队列的最大存储数
# 往队列中添加数据
q.put(1)
q.put(2)
# print(q.full()) # 判断队列是否满了
q.put(3)
q.put(4)
q.put(5)
# print(q.full())
# q.put(6) # 当队列满了之后 再放入数据 不会报错 会原地等待 直到队列中有数据被取走(阻塞态)
print(q.get())
print(q.get())
print(q.get())
print(q.empty()) # 判断队列中的数据是否取完
print(q.get())
print(q.get())
print(q.empty())
# print(q.get_nowait()) # 取值 没有值不等待直接报错
# print(q.get()) # 当队列中的数据被取完之后 再次获取 程序会阻塞 直到有人往队列中放入值
"""
full
get_nowait
empty
都不适用于多进程的情况
"""
from multiprocessing import Process,Queue
def producer(q):
q.put('hello GF~')
def consumer(q):
print(q.get())
if __name__ == '__main__':
q = Queue()
p = Process(target=producer,args=(q,))
c = Process(target=consumer, args=(q,))
p.start()
c.start()
"""
子进程放数据 主进程获取数据
两个子进程相互放 取数据
"""
生产者消费者模型
"""
生产者:生产/制造数据的
消费者:消费/处理数据的
这其中有时会出现下列情况
用大白话讲:做包子的,买包子的
1.做包子远比买包子的多
2.做包子的远比包子的少
供求不平衡的问题
"""
代码示例:
方法一:
使用了jionableQueue方法,
方法二:
#手动为每个进程设置等待:
from multiprocessing import Process,Queue,joinableQueue
import random , time
def producer(name, food ,q):
for i in range(4)
data = f'{name}生产了{food},第{i+1}号'
time.sleep(random.random()) # 生产间隔
q.put(data)
print(data)
def consumer (name,q):
while True:
data=q.get()
if data == None :
print('吃完了,也做完了')
break
print(f'{name}生产了{data})
time.sleep(random.random() #消化时间
q.task_done() # 告诉队列已经从队列中取出了一个数据,并且已经处理完毕
if __name__ == '__main__':
q = JoinableQueue() #创建对象
p = Process(target=producer,args=('大厨egon','馒头',q))
p1 = Process(target=producer,args=('墩子tank','生蚝',q))
# c = Process(target=consumer,args=('小小',q))
c1 = Process(target=consumer,args=('吃货',q))
p.start()
p1.start()
# c.daemon = True
c1.daemon = True
# c.start()
c1.start()
p.join()
p1.join()
q.join() # 等到队列中数据全部取出
# q.put(None)
# q.put(None)
结果如下:
墩子tank生产了生蚝.5号
吃货吃了墩子tank生产了生蚝.5号
大厨egon生产了馒头.4号
吃货吃了大厨egon生产了馒头.4号
墩子tank生产了生蚝.2号
大厨egon生产了馒头.3号
大厨egon生产了馒头.9号
吃货吃了墩子tank生产了生蚝.2号
大厨egon生产了馒头.1号
墩子tank生产了生蚝.7号
吃货吃了大厨egon生产了馒头.3号
吃货吃了大厨egon生产了馒头.9号
吃货吃了大厨egon生产了馒头.1号
墩子tank生产了生蚝.8号
吃货吃了墩子tank生产了生蚝.7号
吃货吃了墩子tank生产了生蚝.8号
Process finished with exit code 0
线程理论
什么是线程
进程线程其实都是虚拟单位,都是用来帮助我们形象的描述某种事物
进程:资源单位
线程:执行单位
将内存比如成工厂
那么进程就相当于是工厂里面的车间
而你的线程就相当于是车间里面的流水线
ps:每个进程都自带一个线程,线程才是真正的执行单位,进程只是在线程运行过程中
提供代码运行所需要的资源
为什么要有线程
开进程
1.申请内存空间 耗资源
2."拷贝代码" 耗资源
开线程
一个进程内可以起多个线程,并且线程与线程之间数据是共享的
ps:开启线程的开销要远远小于开启进程的开销
from threading import Thread
import time
def task(name):
print('%s is running'%name)
time.sleep(3)
print('%s is over'%name)
# 开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内
t = Thread(target=task,args=('egon',))
t.start() # 告诉操作系统开辟一个线程 线程的开销远远小于进程
# 小的代码执行完 线程就已经开启了
print('主线程')
from threading import Thread
import time
class MyThread(Thread):
def __init__(self,name):
super().__init__()
self.name = name
def run(self):
print('%s is running'%self.name)
time.sleep(3)
print('%s is over'%self.name)
t = MyThread('egon')
t.start()
print('主线程')
执行结果:
egon is running
主
egon is running
主
egon is over
egon is over
join方法
from threading import Thread,current_thread,active_count
import time
import os
def task(name,i):
print('%s is running'%name)
# print('子current_thread:',current_thread().name)
# print('子',os.getpid())
time.sleep(i)
print('%s is over'%name)
# 开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内
t = Thread(target=task,args=('egon',1))
t1 = Thread(target=task,args=('jason',2))
t.start() # 告诉操作系统开辟一个线程 线程的开销远远小于进程
t1.start() # 告诉操作系统开辟一个线程 线程的开销远远小于进程
t1.join() # 主线程等待子线程运行完毕
print('当前正在活跃的线程数',active_count())
# 小的代码执行完 线程就已经开启了
print('主')
# print('主current_thread:',current_thread().name)
# print('主',os.getpid())
线程间通信
注意 与进程不同的是 ,同一进程下的多线程是共用该进程下的资源的,
即他们之间使用的可以说是同一名称空间,
from threading import Thread
money = 666
def test():
global money
money = 999
t = Thread(target=task)
t.start()
t.join()
print(money)
执行结果:
999
线程对象及其他方法
from threading import Thread,current_thread
import time
守护线程:
def task(i):
print(current_thread().name)
time.sleep(i)
print('GG')
# for i in range(3):
# t = Thread(target=task,args=(i,))
# t.start()
t = Thread(target=task,args=(1,))
t.daemon = True
t.start()
print('主')
# 主线程运行结束之后需要等待子线程结束才能结束呢?
"""
主线程的结束也就意味着进程的结束
主线程必须等待其他非守护线程的结束才能结束
(意味子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了资源也就销毁了)
"""
举例子:
from threading import Thread
from multiprocessing import Process
import time
def foo():
print(123)
time.sleep(1)
print("end123")
def bar():
print(456)
time.sleep(3)
print("end456")
def run():
print('789')
time.sleep(2)
print('end789')
if __name__ == '__main__':
t1=Thread(target=foo)
t2=Thread(target=bar)
t3= Thread(target=run)
t2.daemon=True
t1.start()
t2.start()
t3.start()
print("main-------开始")
执行结果:
123
456
789
main-------开始
end123
end789
可以看到 尽管我们使用了守护进程,即将主线程设置为t2的守护进程,当主线程死亡,则t2被强制杀死,那么结果就不包含'end456'.
线程互斥锁:
与操作进程互斥锁同理,当我们想要安全的增删改查数据,最后对操作数据的步骤加锁,以保证数据的安全性,操作和进程相同,即创建锁,抢锁,释放锁,
from threading import Thread,Lock
import time
n = 77
def task(mutex):
global n
mutex.acquire() # 抢锁
tmp = n
time.sleep(0.1)
n = tmp - 1
mutex.release() # 释放锁
t_list = []
mutex = Lock() # 示例化一个锁,即创建一个锁
for i in range(77):
t = Thread(target=task,args=(mutex,))
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(n)
并发编程,python的进程,与线程的更多相关文章
- Python 3 并发编程多进程之进程与线程
Python 3 进程与线程 进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的 ...
- Python3 与 C# 并发编程之~ 进程篇
上次说了很多Linux下进程相关知识,这边不再复述,下面来说说Python的并发编程,如有错误欢迎提出- 如果遇到听不懂的可以看上一次的文章:https://www.cnblogs.com/dot ...
- Python3 与 C# 并发编程之~进程先导篇
在线预览:http://github.lesschina.com/python/base/concurrency/1.并发编程-进程先导篇.html Python3 与 C# 并发编程之- 进程篇 ...
- java并发编程笔记(三)——线程安全性
java并发编程笔记(三)--线程安全性 线程安全性: 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现 ...
- Java并发编程(您不知道的线程池操作)
Java并发编程(您不知道的线程池操作) 这几篇博客,一直在谈线程,设想一下这个场景,如果并发的线程很多,然而每个线程如果执行的时间很多的话,这样的话,就会大量的降低系统的效率.这时候就可以采用线程池 ...
- Python的进程与线程--思维导图
Python的进程与线程--思维导图
- 【Java并发编程】之二:线程中断
[Java并发编程]之二:线程中断 使用interrupt()中断线程 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一 ...
- java并发编程笔记(七)——线程池
java并发编程笔记(七)--线程池 new Thread弊端 每次new Thread新建对象,性能差 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM 缺 ...
- java并发编程笔记(五)——线程安全策略
java并发编程笔记(五)--线程安全策略 不可变得对象 不可变对象需要满足的条件 对象创建以后其状态就不能修改 对象所有的域都是final类型 对象是正确创建的(在对象创建期间,this引用没有逸出 ...
随机推荐
- 重学 Java 设计模式:实战单例模式
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 5个创建型模式的最后一个 在设计模式中按照不同的处理方式共包含三大类:创建型模式.结 ...
- 15期day01编程与计算机硬件
一.编程: 1,编程语言:定义:让计算机能像人一样去工作执行某种命令的语音 重点:工作的思维逻辑 编程语言为翻译 简单逻辑汉语 小例子: 接收用户输入的用户名 接收用户输入的密码 判断用户输入的用户名 ...
- 实验三 UML 建模工具的安装与使用
UML 建模工具的安装与使用一. 实验目的1) 学习使用 EA(Enterprise Architect) 开发环境创建模型的一般方法: 2) 理解 EA 界面布局和元素操作的一般技巧: 3) 熟悉 ...
- Rocket - devices - TLBusBypass
https://mp.weixin.qq.com/s/WviVHxlZvsNm8mea2VpfTw 简单介绍TLBusBypass的实现. 1. TLBypassNode TLBypassNode定义 ...
- GTA5侠盗猎车5中文版破解版绿色版汉化版迅雷下载地址种子实测可用
GTA5(侠盗猎车5)中文版下载地址(实测可用) 迅雷下载地址:https://www.90pan.com/b1548988 一定要关闭安全软件并且加入白名单 实测通过,关闭杀毒软件可以完美运行,最好 ...
- HTML中块级行级元素小分类
行内元素列表: <a>标签可定义锚 <abbr>表示一个缩写形式 <acronym>定义只取首字母缩写 <b>字体加粗 <bdo>可覆盖默认 ...
- Java实现 LeetCode 802 找到最终的安全状态 (DFS)
802. 找到最终的安全状态 在有向图中, 我们从某个节点和每个转向处开始, 沿着图的有向边走. 如果我们到达的节点是终点 (即它没有连出的有向边), 我们停止. 现在, 如果我们最后能走到终点,那么 ...
- java实现 历届试题 蓝桥杯 打印十字图
历届试题 打印十字图 题目描述 小明为某机构设计了一个十字型的徽标(并非红十字会啊),如下所示(可参见p1.jpg) 对方同时也需要在电脑dos窗口中以字符的形式输出该标志,并能任意控制层数. 为了能 ...
- Java实现 LeetCode 217 存在重复元素
217. 存在重复元素 给定一个整数数组,判断是否存在重复元素. 如果任何值在数组中出现至少两次,函数返回 true.如果数组中每个元素都不相同,则返回 false. 示例 1: 输入: [1,2,3 ...
- Java实现二分查找(折半查找)
1 问题描述 首先,了解一下何为折半查找?此处,借用<算法设计与分析基础>第三版上一段文字介绍: 2 解决方案 2.1 递归法 package com.liuzhen.chapter4; ...