并发编程
操作系统发展史
基于单核研究
多道技术
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. 突发!HashiCorp禁止在中国使用企业版VAULT软件

    目录 前言 HashiCorp公司介绍 HashiCorp旗下的软件 Provision Secure Connect Run 总结 前言 昨天HashiCorp突然发布一则消息,禁止在中国使用Vau ...

  2. 【汇总】 为园友写的皮肤制作工具 awescnb

    Awescnb, awesome cnblog. 简介 可能许多初来乍到的新手会被博客园经典的风格劝退,或者您是一个老园友,需要为您的博客定制一些功能(例如宣传公众号,文章目录.或者插入几个捐助二维码 ...

  3. 如何开启远程桌面连接功能?windows的远程桌面连接功能使用步骤

    由于远程桌面的诞生,为电脑工作者提供了极大的便利.首先,推荐1款比较适合服务器管理的远程桌面: 可以管理1000+服务器/vps的远程桌面:IIS7远程桌面管理 开启远程桌面功能步骤: 1.右键点击电 ...

  4. jchdl - GSL Node

    https://mp.weixin.qq.com/s/Oa4qgjIUccu5Y-Jlqcyn_A   org.jchdl.model.gsl.core.meta.Node.java   ​​ gen ...

  5. 超干货!为了让你彻底弄懂MySQL事务日志,我通宵肝出了这份图解!

    还记得刚上研究生的时候,导师常挂在嘴边的一句话,"科研的基础不过就是数据而已."如今看来,无论是人文社科,还是自然科学,或许都可在一定程度上看作是数据的科学. 倘若剥开研究领域的外 ...

  6. 数据库之 MySQL --- 视图的原理解析与创建(八)

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 1.什么是视图? 视图:MySQL从5.0.1版本开始提供视图功能.一种虚拟存在的表,行和列的数据来自定 ...

  7. Java实现 蓝桥杯 算法提高 计算超阶乘(暴力)

    试题 算法提高 计算超阶乘 问题描述 计算1*(1+k)(1+2k)(1+3k)-(1+n*k-k)的末尾有多少个0,最后一位非0位是多少. 输入格式 输入的第一行包含两个整数n, k. 输出格式 输 ...

  8. Java 第十一届 蓝桥杯 省模拟赛 小明的城堡

    小明用积木搭了一个城堡. 为了方便,小明在搭的时候用的是一样大小的正方体积本,搭在了一个 n 行 m 列的方格图上,每个积木正好占据方格图的一个小方格. 当然,小明的城堡并不是平面的,而是立体的.小明 ...

  9. Java实现 LeetCode 537 复数乘法(关于数学唯一的水题)

    537. 复数乘法 给定两个表示复数的字符串. 返回表示它们乘积的字符串.注意,根据定义 i2 = -1 . 示例 1: 输入: "1+1i", "1+1i" ...

  10. Java实现 蓝桥杯 算法提高 p1001

    算法提高 P1001 时间限制:1.0s 内存限制:256.0MB 提交此题  当两个比较大的整数相乘时,可能会出现数据溢出的情形.为避免溢出,可以采用字符串的方法来实现两个大数之间的乘法.具体来说 ...