之前的网络编程,服务器端一直不能实现并发的一个效果,借助别人写好的模块,也并不知道这个模块当中发生了什么事?
# 在Python中如何实现并发?
# 并发是什么?
# 想到多进程多线程,首先想到进程,那什么是进程?
# 什么是进程?
# 指的就是就是一个正在运行的程序或者说是程序的运行过程。(即进程是一个抽象的概念,就是用来描述一个程序的运行过程)
# 如果没有这个抽象的概念,怎么描述qq程序整个的运行顺序?
# 有一个程序叫qq程序,他最开始在硬盘里面,启动的时候他由硬盘读到内存里面去了,cpu到内存读他的代码然后运行它
# 怎么就叫一个程序运行起来了?
# 就是由硬盘加载到内存,再由cpu到内存中去取这个程序的代码执行
# cpu,内存,硬盘都是硬件,硬件都是被操作系统控制的,所以qq这个程序从启动到运行再到销毁都是操作系统管理
# 一个程序的运行过程是被操作系统把控着的
# 一个程序的运行过程称之为一个进程
# 所以进程是起源于操作系统,是操作系统最核心的概念,操作系统所有其他的概念都是围绕进程展开的
# 为什么要用进程?
# 为了实现并发
# 如何使用进程?(知识点比较多)
# 1.开启进程的两种方式
# ----------------------------------
# 转到介绍操作系统
# ----------------------------------
计算机操作系统
# 启进程是为了干一个活
# 做一个区分,程序和进程
# 一个程序能称之为一个进程吗?不能,程序是死的,硬盘上躺的那一堆代码那叫程序。
# 什么是进程?程序运行起来才叫进程。
# 什么是操作系统?
# 操作系统是位于计算机硬件与软件之间的控制程序,负责将计算机硬件复杂的操作封装成简单的接口给应用软件去用,起到这么一个承上启下的作用
# 操作系统本身也是一个软件,只不过这个软件非常的独特,帮你管理硬件(cpu怎么运做,硬盘怎么运做,内存怎么运作)都封装成简单的接口
# 给你应用程序调就可以了,这是操作系统的第一大功能。操作硬盘有一个单位叫做文件处理
# 第二大功能是什么?
# 多套应用程序共享一套硬件,操作系统将应用程序对硬件的争抢变得有序化,大家照着顺序来。将多个应用程序对硬件的竞争变的有序
# 操作系统怎么从无到有,发展到今天这个状态
# 第一代计算机:
# 真空管,没有操作系统的概念,没有编程语言
# 背景是第二次世界大战
# 优点:
# 程序员独享计算机
# 缺点:
# 浪费计算机资源
# 此时计算机运行的程序是一个程序完完整整的运行完,另一个程序才能运行,这个称之为串行
# 什么叫串行,一个任务完完整整的运行完毕后,才能运行下一个任务。
# 第二代计算机
# 晶体管,批处理操作系统()
# 第三代计算机
# 多道技术:
# 最开始计算机产生的时候,计算机负责真正计算的是cpu早期是单核的,一个核只能干一个活
# 什么是并发?
# 看起来多个任务是同时运行的即可,单核也可以实现并发
# 什么是并行?
# 真正意义上多个任务的同时运行,只有多核才能实现并行
# write:内容由内存刷到硬盘上
# io操作:输入输出
# cpu的功能是做计算的,一但遇到io操作,cpu是无法执行io操作的。
# io的指令由cpu发出,就只能等着数据内存刷到硬盘,或者由硬盘写入到内存当中
# cpu遇到io要么在原地等,要么去干别的活,应该让cpu去执行别的任务。
# 多道技术的核心思想:
# 1.空间上的复用,指的其实就是多个进程共用同一个内存条
# 2.时间上的复用,指的其实就是多个进程复用同一个cpu的时间
# 分析一下这两个到底代表什么意思?
# 想让cpu能够干十个任务,最好给人的感觉还是这十个任务是同时运行的,怎么做到呢?
# 作为cpu想要工作必须取数据才能工作,得知道要让干的指令代码在哪里放着呢,需要从哪取?应该从内存取,但是最早这是个程序他们的代码在哪里放着?
# 最先在硬盘放着呢,从硬盘取怎么办?cpu的工作模式是那第一个程序的代码,干第一个活,干着干着遇到io了,赶紧利用io的时间去干第二个活
# 但是如果没内存了,所有数据都在硬盘放着,感觉不出十个程序是同时运行的(因为从硬盘读第一个指令的时候,读的时候在运行运行说第一个程序遇到io了
# 再去读第二个代码的时候io的时间过长,cpu到硬盘读的这个io时间过长,就会明显感觉到一种等的感觉)所以运行的程序的代码都应该事先加载到内存中去
# 要保证十个程序的运行一定要保证都得先跑到内存,在这十个程序之间切切切切切,cpu的速度就快了。
# 空间上的复用指的是什么呢?
# 你想要并发执行着十个程序的代码,应该先从硬盘加载到内存里面去,并且每一个程序的内存空间都是独立的,跟别人互相隔离
# 为什么要互相隔离?
# 是多道技术规定的!!
# 为什么一个进程跟一个进程的数据一定要物理界别的内存的隔离,不隔离的话大家都混到一起,一个程序运行起来了叫起了一个进程,起了一个进程是要占内存资源的
# 而内存的空间是有限的,总得在你不用的时候释放出来给别人使用腾地方,如果都到一起,操作系统也是软件,都在内存,可能把操作系统的那一块内存也释放掉了
# 误删导致导致丧失稳定性,其次丧失的就是安全性(用计算机输账号密码才能登进去,是操作系统提供的)
# 时间上的复用,cpu遇到io要切换(可以提升效率),一个进程占用cpu时间太长也会切走(为了实现并发效果,不得已而为之,反而会降低程序的执行效率)。
# cpu的时间片
# 分时操作系统
# 操作系统
# 第四代计算机:
# 个人计算机
-----------------------------------------进程--------
进程理论
# PID 指的是进程在操作系统内对应的一个身份证号
# 进程:一个正在运行的程序或者说是一个程序的运行状态
# 串行:一个任务完完整的运行完毕,才执行下一个任务
# 并发:多个任务看起来像同时运行的,单核就可以实现并发
# 并行:多个任务是真正意义上的同时运行,只有多核才能实现并行
# 进程理论
# 学习进程是为了实现一个程序当中实现多个任务的并发
# 进程的创建
# 1.系统初始化-操作系统刚刚启动的时候
# 2.用户交互式的请求。双击qq就是
# 3.一个批处理的初始化
# 4.一个进程运行的过程当中再开启子进程*****
# 父进程的数据拷贝一份给子进程,当做子进程的全局变量,但是Windows与Linux不同在哪呢,子进程当中的拷贝过去的数据初始状态不是跟父进程状态一模一样的
# 而liunx系统,子进程初始状态跟父进程状态是一样的
# 子进程与父进程运行起来是两个进程,是独立的内存空间
# 子进程初始数据跟父进程是一样的,但子进程创建出来了,子进程内存空间跟父进程内存空间就隔离开了,子进程修改了父进程的数据,但不影响父进程里的数据
# 进程的运行状态:
# 运行态,正在被cpu运行着
# 阻塞态,遇到io
# 就绪态,io完了等着cpu
开启进程的两种方式
# 在一个父进程中如何开启子进程?将原本在父进程的任务并发执行的这个方式
# 开启子进程两种方式,掌握第一种
# Windows操作系统的接口是process,封装了模块
# import multiprocessing
# import threading(线程模块)
# 方式一:、
# 从这个模块下面导类叫Process造对象,造对象起一个进程对象,让子进程里面并发去一个执行任务
from multiprocessing import Process
import time
# 先定义一个任务:
def task(x):
print('%s is running'%x)
time.sleep(3)
print('%s is done'%x)
# 开启子进程:
# 调Process这个类,里面需要target = 进程造出来之后执行的任务是谁?task不要加括号,name=进程名,不写有个默认的,为这个任务传参
# 有两种 args = ()args=元祖,元祖的形式的话,按照位置传(‘子进程’,)如果只有一个参数一定不要忘记就逗号
# 另一种形式 kwargs = {'x':'子进程'}字典的形式k:v
# 这只是类调用产生一个对象
p = Process(target=task,args=('子进程',))
# 要想启动起来。要掉对象下面一个start()方法,开启进程
p.start() #只是在向操作系统发送一个开启子进程的信号
print('主进程')
# 开启之后就有两个进程
# 在windows下开启子进程,他的机制比较特殊,需要
# if __name__ == '__main__':
# p = Process(target=task,args=('子进程',))
# p.start()
# 借助于Process这个类造一个对象,调对象下的一个绑定方法。这个类是模块提供的
# 方式二:
class MyProcess(Process):
def run(self):
print('%s is running' % self.name)
time.sleep(3)
print('%s is done' % self.name)
p = MyProcess()
p.start()
# 继承默认的类,把想要子进程做的任务放run方法里面去
# 区别在于第一种是通用的
# 考虑一个问题,主进程什么时候把自己该干的活干完了?
进程对象相关的属性或方法
# 僵尸进程
# liunx系统,僵尸进程是一种独特的数据结构,子进程在运行完毕以后,保留这个进程的ID号。
# 父进程无法预知子进程什么时候死,而父进程又要知道
# 等所有子进程都死掉,父进程发起一个请求回收
# ps aux |grep 'z'
# top
# 进程之间内存空间是彼此隔离的
from multiprocessing import Process
import time
# 改全局变量
x = 100
def task():
global x
x=0
print(x)
print('over')
if __name__ == '__main__':
p = Process(target=task)
p.start()
time.sleep(3)
print(x)
# join操作
# 进程对象的方法或属性
# p.join
from multiprocessing import Process
import time
# # 一个任务
# def task(x):
# print('%s is running'%x)
# time.sleep(2)
# print('%s is over'%x)
#
# # 开启子进程
# if __name__ == '__main__':
# p = Process(target=task,args=('子进程',))
# p.start()
#
# p.join()#让父进程在原地等待,等到子进程运行完毕后,才执行下一行代码
#
# print('主') #想在子进程运行完毕后执行
# 起好多个进程
from multiprocessing import Process
import time
# 一个任务
def task(x,n):
print('%s is running'%x)
time.sleep(n)
print('%s is over'%x)
# 开启子进程
if __name__ == '__main__':
# 造进程对象
p1 = Process(target=task,args=('子进程1',1))
p2 = Process(target=task,args=('子进程2',2))
p3 = Process(target=task,args=('子进程3',3))
start_time = time.time()
p1.start()
p2.start()
p3.start()
p1.join()#
p2.join()#
p3.join()#
print('主') #想在子进程运行完毕后执行
stop_time = time.time()
print(stop_time-start_time)
# 干重复的事,可以优化
# p1 = Process(target=task,args=('子进程1',1))
# p2 = Process(target=task,args=('子进程2',2))
# p3 = Process(target=task,args=('子进程3',3))
p_l = []#列表里面放进程对象
for i in range(1,4):
p = Process(target=task,args=('子进程%s'%i,i))
p_l.append(p)
p.start()
for p in p_l:#取出来对象,join
p.join()
print('主')
-----------------------------------------线程------
线程理论
开启线程的两种方式
线程对象相关的属性或方法