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之前使用
进程数据是隔离的
互斥锁:
多个进程操作一份数据的时候会出现数据错乱的现象
避免?:将操作数据的部分加锁处理(会将并发变成串行牺牲了效率但是保证了数据的安全)
强锁:acpuire()
释放锁:release()
进程间的通信:
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)
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
都不适用于多进程的情况
"""
进程间通信IPC机制:
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() """
子进程放数据 主进程获取数据
两个子进程相互放 取数据
"""
生产者消费者模型:
from multiprocessing import Process,Queue,JoinableQueue
import random
import time def producer(name,food,q):
for i in range(10):
data = '%s生产了%s%s'%(name,food,i)
time.sleep(random.random())
q.put(data)
print(data) def consumer(name,q):
while True:
data = q.get()
if data == None:break
print('%s吃了%s'%(name,data))
time.sleep(random.random())
q.task_done() # 告诉队列你已经从队列中取出了一个数据 并且处理完毕了 if __name__ == '__main__':
q = JoinableQueue() p = Process(target=producer,args=('大厨','馒头',q))
p1 = Process(target=producer,args=('跟班','生蚝',q))
c = Process(target=consumer,args=('william',q))
c1 = Process(target=consumer,args=('john',q))
p.start()
p1.start()
c.daemon = True
c1.daemon = True
c.start()
c1.start()
p.join()
p1.join() q.join() # 等到队列中数据全部取出
线程:
进程和线程都是虚拟单位,都是用来帮助我们形象的描述某种事物
进程:资源单位
线程:执行单位
将内存比成加工厂,那么进程就是相当于工厂里面的车间,那么线程就是车间里面的流水线
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=('william',))
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('john')
t.start()
print('主')
线程对象方法:开启线程不需要在__main__代码块内,但是习惯性的还是写在__main__代码块内
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=('john',1))
t1 = Thread(target=task, args=('william',2))
t.start() # 告诉操作系统开辟一个线程 线程的开销远远小于进程
t1.start() # 告诉操作系统开辟一个线程 线程的开销远远小于进程
t1.join() # 主线程等待子线程运行完毕
print('当前正在活跃的线程数',active_count())
# 小的代码执行完 线程就已经开启了
print('主')
# print('主current_thread:',current_thread().name)
# print('主', os.getpid())
守护线程:主线程的结束也就意味着进程的结束,主线程必须等待其它非守护线程的结束才能结束(意味着子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了资源也就销毁了)
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 money = 666 def task():
global money
money = 999 t = Thread(target=task)
t.start()
t.join()
print(money) # money变成了999
线程中的互斥锁:
from threading import Thread,Lock
import time n = 100 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(100):
t = Thread(target=task,args=(mutex,))
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(n)
线程中的小例子:
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") if __name__ == '__main__':
t1=Thread(target=foo)
t2=Thread(target=bar)
t1.daemon=True
t1.start()
t2.start()
print("main-------")
这里需要注意的是:主线程要等待非守护线程的结束才会结束所以在这里面end123也是会输出的
python基础--线程、进程的更多相关文章
- python基础(16)-进程&线程&协程
进程之multiprocessing模块 Process(进程) Process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建. 介绍 初始化参数 Process([group [, t ...
- python基础之进程、线程、协程篇
一.多任务(多线程) 多线程特点:(1)线程的并发是利用cpu上下文的切换(是并发,不是并行)(2)多线程执行的顺序是无序的(3)多线程共享全局变量(4)线程是继承在进程里的,没有进程就没有线程(5) ...
- Python(线程进程3)
四 协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切 ...
- python之线程进程协成
线程与进程 什么是线程 线程是进程一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位,线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源,但是它可与同属一个线程的 ...
- python基础(32):进程(二)
1. multiprocess模块 仔细说来,multiprocess不是一个模块而是python中一个操作.管理进程的包. 之所以叫multi是取自multiple的多功能的意思,在这个包中几乎包含 ...
- Python自动化 【第九篇】:Python基础-线程、进程及python GIL全局解释器锁
本节内容: 进程与线程区别 线程 a) 语法 b) join c) 线程锁之Lock\Rlock\信号量 d) 将线程变为守护进程 e) Event事件 f) queue队列 g) 生 ...
- python基础23 -----进程和线程
一.进程 1.什么是进程? 1.1 进程就是一个程序在一个数据集上的一次动态执行过程.进程一般由程序.数据集.进程控制块三部分组成. 1.2 程序是指进程需要完成那些功能以及如何完成. 1.3 数据集 ...
- Python菜鸟之路:Python基础-线程、进程、协程
上节内容,简单的介绍了线程和进程,并且介绍了Python中的GIL机制.本节详细介绍线程.进程以及协程的概念及实现. 线程 基本使用 方法1: 创建一个threading.Thread对象,在它的初始 ...
- Python基础—线程、进程和协程
今天已是学习Python的第十一天,来干一碗鸡汤继续今天的内容,今天的鸡汤是:超越别人对你的期望.本篇博客主要介绍以下几点内容: 线程的基本使用: 线程的锁机制: 生产者消费之模型(队列): 如何自定 ...
- python基础-守护进程、守护线程、守护非守护并行
守护进程 1.守护子进程 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic pro ...
随机推荐
- 关于Spring Cloud Feign的一些记录!
学习Spring Cloud Feign过程中,相关资料都会反复强调:微服务调用的话(@FeignClient) 客户端方法的返回值和服务端方法的返回值还有方法名之类的都是要求一致的! 关于方法名是 ...
- Apache Pig学习笔记(二)
主要整理了一下,pig里面的一些关键词的含义和用法,pig虽然是一种以数据流处理为核心的框架,但数据库的大部分关键词和操作,在pig里面基本上都能找到对应的函数,非常灵活与简洁,春节前的最后一篇文章 ...
- NoSQL 文档数据库
- 跟我一起学习webpack输出动态HTML(三)
跟着之前的项目来 我们没打包一次就会生成一个bundile.js,我们要更新最新的代码不希望有缓存,那么这个时候我们就是更改资源的URL, 每当代码发生变化时,相应的hash也会发生变化.这个时候我们 ...
- Create STKNetDiskC Instance Error
关于Create STKNetDiskC Instance Error错误的解决方法 这个错误可能出现在: AM8 附件直接存网盘的时候 报错 解决方法步骤如下: 在出现该错误的机器上,先将AM及 m ...
- php循环语句(一)
PHP 循环语句 什么是循环语句? 在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句.一组被重复执行的语句称之为循环体,能否继续重复,决定循环的终止条件.循环结构是在一定 ...
- c语言学习笔记 - 顺序查找和哨兵查找比较
今天学习C时用到了顺序查找和哨兵查找,做了一个比较,主要是学习下哨兵查找法 例如在一个数组里查找一个元素,没找到返回-1,找到了则返回这个数组的下标也就是键值. 用循序查找法: void arr_se ...
- 导出SQL Server中所有Job的最简单方法
应用场景: 在将源SQL Server数据库服务器中的所有Job(作业)迁移至目标数据库服务器的过程中,需要先将这些Job导出为SQL脚本. 操作步骤: 1.在Microsoft SQL Server ...
- SDF与MDF的区别
标签: 杂谈 数据库扩展名为.sdf,是一个基于sql server compact edition的数据库文件,不需要安装SQL Server就可以用 基于服务的数据库扩展名为.mdf,是基于S ...
- 深入浅出 Java Concurrency (7): 锁机制 part 2 AQS[转]
在理解J.U.C原理以及锁机制之前,我们来介绍J.U.C框架最核心也是最复杂的一个基础类:java.util.concurrent.locks.AbstractQueuedSynchronizer. ...