并发编程
操作系统发展史
基于单核研究
多道技术
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的进程,与线程的更多相关文章

  1. Python 3 并发编程多进程之进程与线程

    Python 3 进程与线程 进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的 ...

  2. Python3 与 C# 并发编程之~ 进程篇

      上次说了很多Linux下进程相关知识,这边不再复述,下面来说说Python的并发编程,如有错误欢迎提出- 如果遇到听不懂的可以看上一次的文章:https://www.cnblogs.com/dot ...

  3. Python3 与 C# 并发编程之~进程先导篇

      在线预览:http://github.lesschina.com/python/base/concurrency/1.并发编程-进程先导篇.html Python3 与 C# 并发编程之- 进程篇 ...

  4. java并发编程笔记(三)——线程安全性

    java并发编程笔记(三)--线程安全性 线程安全性: ​ 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现 ...

  5. Java并发编程(您不知道的线程池操作)

    Java并发编程(您不知道的线程池操作) 这几篇博客,一直在谈线程,设想一下这个场景,如果并发的线程很多,然而每个线程如果执行的时间很多的话,这样的话,就会大量的降低系统的效率.这时候就可以采用线程池 ...

  6. Python的进程与线程--思维导图

    Python的进程与线程--思维导图

  7. 【Java并发编程】之二:线程中断

    [Java并发编程]之二:线程中断 使用interrupt()中断线程 ​ 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一 ...

  8. java并发编程笔记(七)——线程池

    java并发编程笔记(七)--线程池 new Thread弊端 每次new Thread新建对象,性能差 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM 缺 ...

  9. java并发编程笔记(五)——线程安全策略

    java并发编程笔记(五)--线程安全策略 不可变得对象 不可变对象需要满足的条件 对象创建以后其状态就不能修改 对象所有的域都是final类型 对象是正确创建的(在对象创建期间,this引用没有逸出 ...

随机推荐

  1. 重学 Java 设计模式:实战单例模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 5个创建型模式的最后一个 在设计模式中按照不同的处理方式共包含三大类:创建型模式.结 ...

  2. 15期day01编程与计算机硬件

    一.编程: 1,编程语言:定义:让计算机能像人一样去工作执行某种命令的语音 重点:工作的思维逻辑 编程语言为翻译 简单逻辑汉语 小例子: 接收用户输入的用户名 接收用户输入的密码 判断用户输入的用户名 ...

  3. 实验三 UML 建模工具的安装与使用

    UML 建模工具的安装与使用一. 实验目的1) 学习使用 EA(Enterprise Architect) 开发环境创建模型的一般方法: 2) 理解 EA 界面布局和元素操作的一般技巧: 3) 熟悉 ...

  4. Rocket - devices - TLBusBypass

    https://mp.weixin.qq.com/s/WviVHxlZvsNm8mea2VpfTw 简单介绍TLBusBypass的实现. 1. TLBypassNode TLBypassNode定义 ...

  5. GTA5侠盗猎车5中文版破解版绿色版汉化版迅雷下载地址种子实测可用

    GTA5(侠盗猎车5)中文版下载地址(实测可用) 迅雷下载地址:https://www.90pan.com/b1548988 一定要关闭安全软件并且加入白名单 实测通过,关闭杀毒软件可以完美运行,最好 ...

  6. HTML中块级行级元素小分类

    行内元素列表: <a>标签可定义锚 <abbr>表示一个缩写形式 <acronym>定义只取首字母缩写 <b>字体加粗 <bdo>可覆盖默认 ...

  7. Java实现 LeetCode 802 找到最终的安全状态 (DFS)

    802. 找到最终的安全状态 在有向图中, 我们从某个节点和每个转向处开始, 沿着图的有向边走. 如果我们到达的节点是终点 (即它没有连出的有向边), 我们停止. 现在, 如果我们最后能走到终点,那么 ...

  8. java实现 历届试题 蓝桥杯 打印十字图

    历届试题 打印十字图 题目描述 小明为某机构设计了一个十字型的徽标(并非红十字会啊),如下所示(可参见p1.jpg) 对方同时也需要在电脑dos窗口中以字符的形式输出该标志,并能任意控制层数. 为了能 ...

  9. Java实现 LeetCode 217 存在重复元素

    217. 存在重复元素 给定一个整数数组,判断是否存在重复元素. 如果任何值在数组中出现至少两次,函数返回 true.如果数组中每个元素都不相同,则返回 false. 示例 1: 输入: [1,2,3 ...

  10. Java实现二分查找(折半查找)

    1 问题描述 首先,了解一下何为折半查找?此处,借用<算法设计与分析基础>第三版上一段文字介绍: 2 解决方案 2.1 递归法 package com.liuzhen.chapter4; ...