Python Day34

UDP协议:

 用户数据报协议,是OSI模型中属于传输层的协议。提供不可靠的,不要求顺序的,数据量小的,速度快的传输服务。

不可靠:发送完成后不需要确认信息,并且立即删除缓存中的数据。

不要求顺序:当一个数据较大时,会分为多个数据报来传输,对方无法获知数据的顺序,

以及是否完整。

数据量较小的:数据越大,越容易丢包,所以尽量发送数据量小的建议不要超过1472、

速度快:相对于TCP来说不需要确认信息,不需要建立,甚至不管收不到,只管发,所以传输效率高。

通讯流程:

如果TCP比喻为手机打电话的过程,那么UDP可以看做是对讲机

1.买机器  创建UDP的socket

2.固定频道    bind一个ip和端口

3.收发数据      recvfrom   sendto

接收:

1.买机器   创建UDP的socket

2.收发数据  recvfrom sendto

注意:不能先收,要收数据,必须明确端口号,没有端口号是不可能使用网络服务的。

TCP与UDP的其他区别:

1.不会粘包,每次发送都是一个独立的数据报

2.不需要建立连接

TCP:对数据完整性要求较高:在线支付,文字信息

UDP:对数据不要完整性,但是要快:视频,语音,游戏

DNS:

域名解析服务器

域名就是一串有规律的字符串,用来绑定IP,目的是为了方便记忆。

域名解析服务器 就是帮你把域名转换为ip地址,本质上就是一个大型的数据库系统,里面有域名和IP的对应关系

一台机器性能有限:

分为:

  根域名服务器  只存储顶级域名服务器的信息

  顶级域名服务器  只存储二级域名服务器

  二级域名服务器  只存储三级域名服务器

  三级域名  通常直接存储具体的ip信息

  本地DNS  用于加速解析

自己搭建DNS的作用:

  1.CDN 内容分发网络   就是在你的周围建立更多镜像服务

  2.集群

操作系统:

也是一个软件,受代码保护的不能随意修改,代码量巨大,内核就有500万以上

长寿,一旦完成一般不改。

操作系统发展史

1.第一带计算机 真空管和穿孔卡片 没有进程 没有操作系统

2.第二代计算机 7094 1401 晶体管 批处理系统

输入输出 以及计算设备 不能互联 需要人参与 一批一批的处理 开发效率慢 并且串行执行

3.第三代计算机 集成电路 与多道技术

多终端联机 spooling 同一台机器既能进行科学计算 又能做字符处理 通用计算机

多道技术 解决串行导致的效率低下问题

多用户终端 可以同时为多个用户提供服务 每个用户以为自己独享一台计算机

4.第四代 个人电脑

大规模使用了集成电路,大多都提供了GUI界面

多道技术:

产生背景:所有程序串行,导致资源浪费。目的是让多个程序可以并发执行,同时处理多个任务。

关键技术:

空间复用:指的是 同一时间内存中加载多个不同程序数据。每个进程间内存区域相互隔离,物理层面的隔离。

时间复用:切换加保存

切换条件:1.一个进程执行过程中遇到了IO操作,切换到其他进程

2.运行时间过长,会被操作系统强行剥夺执行权力

单纯的切换不够,必须在切换前保存当前的状态,以便于回复执行。

进程:

一个正在被运行的程序就称之为进程,是程序具体执行过程,一种抽象概念,进程来自于操作系统

多进程:

进程与程序的区别:

程序就是一堆计算机可以识别文件,程序在没有运行时就是一堆躺在硬盘上的二进制数据,

运行的时将数据从硬盘读入内存,然后cpu再将数据从内存读出并执行指令。

一旦程序运行就有了进程,一个程序可以多次运行但进程与进程之间是独立的。

当我们右键运行了一个py文件时,其实启动的是python解释器,你的py文件其实是当作参数传给了解释器。

阻塞,非阻塞,并行,并发:

阻塞:就是程序遇到io操作,非阻塞就是程序没有遇到io操作。并发:多个任务同时发生,但不是同时执行本质上是切换执行,只是速度很快。

并行:多个任务真正的同时执行,必须具备多核CPU,才可能并行。

并发,并行说的是任务的处理方式。

程序员永恒的话题:

提高效率,根本方法就是让程序尽可能处于运行状态。

减少IO 尽可能多占用CPU时间,缓冲区就是用于减少IO操作的。

PID和PPID:

PID:

在一个操作系统中通常都会运行多个应用程序,也就是多个进程,那么如何来区别进程呢?

系统会给每一个进程分配一个进程编号即PID,如同人需要一个身份证号来区分。

验证:

tasklist用于查看所有的进程信息。

taskkill/f/pid/ pid   该命令可以用于结束指定进程。

在python中可以使用os模块来获取pid

import  os

print(os.getpid())

PPID:

当一个进程a开启了另一个进程b时,a称为b的父进程,b称为a的子进程,在python中可以通过os模块来获取父进程的pid。

import os

print("self", os.getppid()) 

如果是在pycharm中运行的py文件,那pycharm就是这个python.exe的父进程,当然你可以从cmd

中来运行py文件,那此时cmd就是python.exe的父进程。

并发与并行,阻塞与非阻塞:

并发指的是多个事件同时发生了:

例如洗衣服和做饭,同时发生了,但本质上是两个任务在切换,给人的感觉是同时在进行着,也被称为伪并行。

并行指的是,多个事情同时进行着:

例如一个人在写代码而另一个人在写书,这2个事情是同时进行的,要注意的是一个人是无法真正的并行执行任务的,在计算机中单核CPU也是无法真正并行的,之所以单核CPU也能同时运行qq和微信,其实就是并发。

阻塞与非阻塞指的是程序的状态

进程有三种状态:

就绪态,运行态和阻塞态


多道技术会在进程执行时间过长或遇到IO时自动切换其他进程,意味着IO操作与进程被剥夺CPU执行权都会造成进程无法继续执行。

进程相关理论:

但凡是硬件,都需要有操作系统去管理,只要有操作系统,就有进程的概念,就需要有创建进程的方式 ,一些操作系统只为一个应用程序设计,比如微波炉中的控制器,一旦启动微波炉,进程就存在。

而对于通用系统(跑很多应用程序),需要有系统运行过程中创建或撤销进程的能力,主要分为4种形式创建新的进程

  1. 系统初始化(查看进程linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件、web页面、新闻、打印)

  2. 一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)

  3. 用户的交互式请求,而创建一个新进程(如用户双击暴风影音)

  4. 一个批处理作业的初始化(只在大型机的批处理系统中应用)

无论哪一种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建,

  1. 在UNIX中该系统调用是:fork,fork会创建一个与父进程一模一样的副本,二者有相同的存储映像、同样的环境字符串和同样的打开文件(在shell解释器进程中,执行一个命令就会创建一个子进程)

  2. 在windows中该系统调用是:CreateProcess,CreateProcess既处理进程的创建,也负责把正确的程序装入新进程。

关于创建的子进程,UNIX和windows

  1.相同的是:进程创建后,父进程和子进程有各自不同的地址空间(多道技术要求物理层面实现进程之间内存的隔离),任何一个进程的在其地址空间中的修改都不会影响到另外一个进程。

  2.不同的是:在UNIX中,子进程的初始地址空间是父进程的一个副本,提示:子进程和父进程是可以有只读的共享内存区的。但是对于windows系统来说,会重新加载程序代码。

进程的销毁:

  1. 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)

  2. 出错退出(自愿,python a.py中a.py不存在)

  3. 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try...except...)

  4. 被其他进程杀死(非自愿,如kill -9)

进程的层次结构

无论UNIX还是windows,进程只有一个父进程,不同的是:

  1. 在UNIX中所有的进程,都是以init进程为根,组成树形结构。父子进程共同组成一个进程组,这样,当从键盘发出一个信号时,该信号被送给当前与键盘相关的进程组中的所有成员。

  2. 在windows中,没有进程层次的概念,所有的进程都是地位相同的,唯一类似于进程层次的暗示,是在创建进程时,父进程得到一个特别的令牌(称为句柄),该句柄可以用来控制子进程,但是父进程有权把该句柄传给其他子进程,这样就没有层次了。

python中实现多进程

在一个应用程序中可能会有多个任务需要并发执行,但是对于操作系统而言,一个进程就是一个任务,CPU会从上往下依次执行代码,当代码中遇到IO操作时,操作系统就会剥夺CPU执行权给其他应用程序,这样对于当前应用程序而言,效率就降低了,如何使得程序既能完成任务又不降低效率呢?答案就是让把当前程序中的耗时操作交給子进程来完成,如此当前应用程序可以继续执行其他任务

python中开启子进程的两种方式

方式1:

实例化Process类

from multiprocessing import Process
import time

def task(name):
print('%s is running' %name)
time.sleep(3)
print('%s is done' %name)
if __name__ == '__main__':
# 在windows系统之上,开启子进程的操作一定要放到这下面
# Process(target=task,kwargs={'name':'egon'})
p=Process(target=task,args=('jack',))
p.start() # 向操作系统发送请求,操作系统会申请内存空间,然后把父进程的数据拷贝给子进程,作为子进程的初始状态
print('======主')

 

方式2:

继承Process类 并覆盖run方法

from multiprocessing import Process
import time

class MyProcess(Process):
def __init__(self,name):
super(MyProcess,self).__init__()
self.name=name

def run(self):
print('%s is running' %self.name)
time.sleep(3)
print('%s is done' %self.name)
if __name__ == '__main__':
p=MyProcess('jack')
p.start()
print('主')

join函数

调用start函数后的操作就由操作系统来玩了,至于何时开启进程,进程何时执行,何时结束都与应用程序无关,所以当前进程会继续往下执行,join函数就可以是父进程等待子进程结束后继续执行

 

from multiprocessing import Process
def task(n):
print('%s is runing' %n)
time.sleep(n)

if __name__ == '__main__':
start_time=time.time()
p1=Process(target=task,args=(1,),name='任务1')
p1.start() # 启动进程
print(p1.pid) # 获取进程pid
print(p1.name) # 获取进程名字
p1.terminate() # 终止进程
p1.join() # 提高优先级
print(p1.is_alive()) # 获取进程的存活状态
print('主')

孤儿进程与僵尸进程(了解)

什么是孤儿进程

孤儿进程指的是开启子进程后,父进程先于子进程终止了,那这个子进程就称之为孤儿进程

例如:qq聊天中别人发给你一个链接,点击后打开了浏览器,那qq就是浏览器的父进程,然后退出qq,此时浏览器就成了孤儿进程

孤儿进程是无害的,有其存在的必要性,在父进程结束后,其子进程会被操作系统接管。

 

什么是僵尸进程

僵尸进程指的是,当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被操作系统接管,子进程退出后操作系统会回收其占用的相关资源!

僵尸进程的危害:

由于子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束. 那么会不会因为父进程太忙来不及wait子进程,或者说不知道 子进程什么时候结束,而丢失子进程结束时的状态信息呢? 不会。因为UNⅨ提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息, 就必然可以得到。这种机制就是: 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)。直到父进程通过wait / waitpid来取时才释放. 但这样就导致了问题,如果进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生[僵死进程],将因为没有可用的进程号而导致系统不能产生新的进程. 此为僵尸进程的危害,应当避免。

猜你喜欢

转载自www.cnblogs.com/xinfan1/p/10957087.html