美文网首页
第九篇 异常处理和并发编程1

第九篇 异常处理和并发编程1

作者: 张大志的博客 | 来源:发表于2018-06-14 17:05 被阅读0次

一、异常处理

#1 什么是异常:程序运行时发生错误的信号(一旦出错,就会产生一个异常,
# 如果该异常没有被应用程序处理,那么该异常才会抛出来,程序也随之终止)
print('=====>')
print('=====>')
print('=====>')
aaa
print('=====>')
print('=====>')
print('=====>')

#2 异常分类
#分类一:针对语法上的异常,应该在程序执行前就解决掉
try:
    print('asdfasdf'
except Exception: #except后有一个万能的异常Exception
    pass
执行结果:还会报错

#分类二:逻辑异常,try...except
# xxx #NameError

# int('xxxxxxx') #valueError

# l=[]
# l[111111] #IndexError

# d={}
# d['a'] #keyError

# 1/0 #ZeroDivisionError:

# import os
# os.xxxxxxxxxxx #AttributeError:

#处理异常的方式:try 。。。except

try:
    print('===>1')
    print('===>2')
    l=[]
    l[123] #IndexError
    print('===>3')
except AttributeError as x:
    print(x)      #打印异常的值
except IndexError as y:
    print(y)
# except Exception as z:   #万能异常
#     print('Ex',z)
else:
    print('被检测的代码块没有发生异常时执行else的代码')
print('====>4')

#finally
try:
    print('===>1')
    print('===>2')
    cursor= connect(数据)
    cursor.excute(sql)
    cursor.excute(sql)
    cursor.excute(sql)
    cursor.excute(sql)
    print('===>3')  #因为上面有异常,此代码不会执行


except Exception:   #万能异常
    print('异常发生时执行的代码')
    # cursor.close()
finally: #不管程序是否出错,都会执行finally的代码
    cursor.close()    #回收资源

#自定义异常
class MySQL_CONN_ERROR(BaseException): #定义一个类,继承父类BaseException
    def __init__(self,value):
        self.value=value

    def __str__(self): #定义报异常的格式
        return '出错啦老铁:%s' %self.value

if 2 > 1:
    # raise TypeError('类型错误')  #自己手动触发一个异常
      raise MySQL_CONN_ERROR('数据库连接错误')

#断言
res=[]
assert len(res) > 0  #如果assert上面的代码有问题,就会报异常,用于调试用
res[0]
res[1]

二、基于udp协议的套接字通讯

前提储备
a,b = (1,2)
print(a)
print(b)
执行结果:
1
2
image.png
#服务端.py
from socket import *

server=socket(AF_INET,SOCK_DGRAM) #SOCK_DGRAM表示udp协议
server.bind(('127.0.0.1',8080))

# server.listen(5) #udp没有连接,不用监听
# server.accept() #udp没有

# while True: #udp没有连接,更不可能有连接循环了
    # server.accept() #udp没有

while True: #通信循环
    msg,client_addr=server.recvfrom(1024) #server.recvfrom(1024)这个函数的返回值是一个元组,里面是(收到消息的内容,发送端的ip和端口)
    print(msg)
    server.sendto(msg.upper(),client_addr)

#客户端.py
from socket import *

client=socket(AF_INET,SOCK_DGRAM)
# client.connect(('127.0.0.1',8080)) #udp没有连接

while True:
    msg=input('>>: ').strip()
    client.sendto(msg.encode('utf-8'),('127.0.0.1',8080))

    msg,server_addr=client.recvfrom(1024)
    print(msg)
总结:udp协议没有连接,发消息时都要指定对方的ip和端口,并且允许发空消息

三、udp协议不会粘包

#服务端.py
from socket import *

server=socket(AF_INET,SOCK_DGRAM) #udp协议叫数据报协议,tcp协议叫流式协议
server.bind(('127.0.0.1',8080))

msg1,client_addr=server.recvfrom(5)  #当收的限制小于5时,windows客户端会报错,linux会少数据
msg2,client_addr=server.recvfrom(1024)
msg3,client_addr=server.recvfrom(1024)

print(msg1)
print(msg2)
print(msg3)

#客户端.py
from socket import *

client=socket(AF_INET,SOCK_DGRAM) #数据报协议

client.sendto('hello'.encode('utf-8'),('127.0.0.1',8080))  #一个sendto就是一个独立的包,服务端也要有一个对应的recvfrom去接收这个包
client.sendto('world'.encode('utf-8'),('127.0.0.1',8080))
client.sendto('egon'.encode('utf-8'),('127.0.0.1',8080))

Tcp和udp的区别
Tcp协议是可靠的协议。因为发送完消息后对方会发送一个确认包,收到确认包后才会从内存中删除这个消息。如果对方没有发确认包,过几秒钟后会重发这个消息,而udp协议,发完就不管了。不管对方收没收到消息都会从内存中删除这个信息,所以udp协议会丢包,但udp协议传输的快


image.png

Udp协议有效传输的数据是512个字节,所以DNS查询的根域只有13台服务器,因为DNS的查询功能是基于udp协议,查询时要包含着13台根域的详细信息,多一台就会超过512个字节

四、进程理论

操作系统的作用提供接口,管理进程


image.png

并发的本质就是保存状态加切换
必备的理论基础:
一 操作系统的作用:
1:隐藏丑陋复杂的硬件接口,提供良好的抽象接口
2:管理、调度进程,并且将多个进程对硬件的竞争变得有序
二 多道技术:
1.产生背景:针对单核,实现并发
ps:
现在的主机一般是多核,那么每个核都会利用多道技术
有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度到这个程序,但会被调度到4个cpu中的任意一个,具体由操作系统调度算法决定。
2.空间上的复用:如内存中同时有多道程序
3.时间上的复用:复用一个cpu的时间片
强调:遇到io切,占用cpu时间过长也切,核心在于切之前将进程的状态保存下来,这样才能保证下次切换回来时,能基于上次切走的位置继续运行
进程:正在进行的一个过程或者说一个任务。而负责执行任务则是cpu。
程序仅仅只是一堆代码而已,而进程指的是程序的运行过程。
进程的创建
一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)


image.png
要提升效率,要让进程尽可能的处于就绪态,减少阻塞态
并发与并行

无论是并行还是并发,在用户看来都是'同时'运行的,不管是进程还是线程,都只是一个任务而已,真是干活的是cpu,cpu来做这些任务,而一个cpu同一时刻只能执行一个任务
一 并发:是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发,(并行也属于并发)
二 并行:同时运行,只有具备多个cpu才能实现并行
单核下,可以利用多道技术,多个核,每个核也都可以利用多道技术(多道技术是针对单核而言的)
有四个核,六个任务,这样同一时间有四个任务被执行,假设分别被分配给了cpu1,cpu2,cpu3,cpu4,一旦任务1遇到I/O就被迫中断执行,此时任务5就拿到cpu1的时间片去执行,这就是单核下的多道技术,而一旦任务1的I/O结束了,操作系统会重新调用它(需知进程的调度、分配给哪个cpu运行,由操作系统说了算),可能被分配给四个cpu中的任意一个去执行

五、开启子进程的两种方式

##开启子进程的方式一:
from multiprocessing import Process
import time,random

def piao(name):
    print('%s is piaoing' %name)
    time.sleep(random.randint(1,3))
    print('%s is over' %name)

if __name__ == '__main__':   #windows下开子进程一定要导入 '__main__',记住就可以,只的是此文件做为模块被导入时不会执行下面的代码,只有当做文件运行时才会执行下面的代码
    # p=Process(target=piao,kwargs={'name':'alex'})  #kwargs是以字典的方式给函数传参数
    p=Process(target=piao,args=('alex',))  #args是以位置参数的方式传参数,调用Process类产生一个创建子进程的对象p
    p.start() #仅仅只是向操作系统发送了一个创建子进程p的信号
    print('主')
执行结果:
主
alex is piaoing
alex is over
父进程是给子进程收尸的

#开启子进程的方式二:
from multiprocessing import Process
import time,random

class MyProcess(Process): #定义一个类继承Process类
    def __init__(self,name):
        super(MyProcess,self).__init__()   #继承父类的init方法
        self.name=name

    def run(self):
        print('%s is piaoing' %self.name)
        time.sleep(random.randint(1,3))   #随机的睡[1,3)
        print('%s is over' % self.name)

if __name__ == '__main__':
    p=MyProcess('P1')
    p.start() #仅仅只是向操作系统发送了一个创建子进程p的信号,就会触发对象下的方法run
    print('主')

六、多进程实现并发的套接字通讯

思路:要实现并发,就要创建多个子进程去执行任务
#服务器.py
from socket import *
from multiprocessing import Process

def talk(conn,addr):
    while True:
        try:
            data=conn.recv(1024)
            if not data:break
            conn.send(data.upper())
        except Exception:   #监控异常,如果客户端主动断开会报异常,为了避免报异常需要进行异常处理
            break
    conn.close()

def server():
    s=socket()
    s.bind(('127.0.0.1',8080))
    s.listen(5) #指的是客户端一下子来了好多个,一次只能处理5个连接
    while True:
        conn,addr=s.accept()   #s.accept()函数的返回值是一个元组,(套接字链接,(客户端的ip,端口))
        print('客户端 %s:%s' %(addr[0],addr[1]))
        p=Process(target=talk,args=(conn,addr))    #创建一个子进程,去干收消息和发消息的活
        p.start()
    s.close()

if __name__ == '__main__':
    server()

# 客户端.py
from socket import *

c = socket()   #默认是tcp协议,不用传参也可以
c.connect(('127.0.0.1', 8080))

while True:
    msg=input('>>: ').strip()
    if not msg:continue
    c.send(msg.encode('utf-8'))
    data=c.recv(1024)
    print(data.decode('utf-8'))

c.close()
这么写有一个问题。就是如果客户端有10000个,就要开一万个子进程去执行任务,这样机器早都崩掉了

七、进程对象的其他方法

#Join方法
from multiprocessing import Process
import time,random

def piao(name):
    print('%s is piaoing' %name)
    time.sleep(random.randint(1,3))
    print('%s is over' % name)


if __name__ == '__main__':
    p1=Process(target=piao,args=('alex1',))
    p1.start()
    p1.join()  #指的是父进程等待子进程执行完之后父进程才结束
    print('主') 
执行结果:
alex1 is piaoing
alex1 is over
主

from multiprocessing import Process
import time,random

def piao(name):
    print('%s is piaoing' %name)
    time.sleep(random.randint(1,3))
    print('%s is over' % name)

if __name__ == '__main__':
    p1=Process(target=piao,args=('alex1',))
    p2=Process(target=piao,args=('alex2',))
    p3=Process(target=piao,args=('alex3',))

    #串行执行
    # p1.start()
    # p1.join()
    # p2.start()
    # p2.join()
    # p3.start()
    # p3.join()

    #并发执行
    p1.start()
    p2.start()
    p3.start()
    p3.join()
    p1.join()
    p2.join()

#简单写法,利用for循环
p_l=[p1,p2,p3] #定义一个列表
for p in p_l:
    p.start()
for p in p_l:
    p.join()
print('主')

#证明进程之间的内存空间是隔离的
from multiprocessing import Process
import time,random

n=100
def task():
    global n #声明是全局变量
    n=0  #改全局变量n的值

if __name__ == '__main__':
    p=Process(target=task)  #产生创建子进程的对象
    p.start() #创建子进程,就会运行task函数,改变全局变量n的值为0
    p.join()  #父进程等待子进程运行完毕后才运行父进程的打印操作
    print('父',n)  #打印父进程内存空间全局变量n的值
执行结果为:父 100
说明创建子进程只是更改自己内存空间中n的值,不会改变父进程中内存空间变量n的值,说明子进程和父进程的内存空间是隔离的

#进程的其他方法和属性
#pid
from multiprocessing import Process
import time,random
import os

def task():
    print('%s is running parent[%s]' %(os.getpid(),os.getppid()))

if __name__ == '__main__':
    p=Process(target=task)
    p.start()
    print(p.pid) #p这个进程的id
    print('主',os.getpid()) #查看python文件的id
    print(os.getppid()) #pycharm的进程id
    time.sleep(1000)

#终止子进程及查看子进程是否存活
from multiprocessing import Process
import time,random
import os

def task():
    print('%s is running ' %(os.getpid()))
    time.sleep(10)

if __name__ == '__main__':
    p=Process(target=task,name='xxxxxxxxxxxxx')
    p.start()
    p.terminate()  #停止子进程,通常不会进行此操作
    time.sleep(1)  #不停止一秒的话,还没来得及干死子进程就查看是否存活,会显示True
    print(p.is_alive())  #查看子进程是否存活
    print(p.name)
    print('主')

八、进程池

#程序的执行方式:
#一:串行执行
#二:并行执行

#同步调用:提交一个任务后,在原地等着,等到该任务运行完毕,拿到结果以后,再执行下一行代码
#异步调用:提交一个任务后,不用在原地等着,直接执行下一行代码,结果呢?
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor,Executor
import time,os,random

def task(i):
    print('%s is running %s' %(os.getpid(),i))
    time.sleep(random.randint(1,3))
    return i**2

if __name__ == '__main__':
    print(os.cpu_count())  #查看cpu的核心数,本机有4个
    pool=ProcessPoolExecutor()  #规定进程池的大小,没有参数默认就是cpu的核心数,进程池是规定同一时间最多可以开多少个进程

    objs=[]
    for i in range(10): #0-9
        obj=pool.submit(task,i) #异步的方式提交任务,会执行task函数,但进程池只有4个,同一时间只有4个进程可以执行任务,obj等于task函数的返回值
        objs.append(obj)  #将task函数的返回值append到列表中

        # res=pool.submit(task,i).result() #同步方式提交任务,会拿到一个结果res,拿到结果后才执行下一个任务
        # print(res)
    pool.shutdown(wait=True) #shutdown代表不允许再往进程池里提交任务,wait=True就是join的意思:父进程等待任务都执行完毕
    print('主')
    for obj in objs:
        print(obj.result())  #最后打印任务的结果
进程池用来开子进程去执行任务

九、paramiko模块的使用

#基于用户名密码连接,远程执行命令
import paramiko  #首先要在parcharm中安装此模块,安装方法
image.png
# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname='66.112.215.110', port=8799, username='root', password='xx')

# 执行命令

while True:
    cmd=input('>>: ').strip()
    stdin, stdout, stderr = ssh.exec_command(cmd)  #将命令的执行结果保存到标准输出
    # 获取命令结果
    result = stdout.read()  #充标准输出中读命令的执行结果
    print(result.decode('utf-8'))
 ssh.close() # 关闭连接

#基于密钥登录
import paramiko

private_key = paramiko.RSAKey.from_private_key_file(r'C:\\id_rsa')

# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname='123.56.157.199', port=22022, username='root', pkey=private_key)

# 执行命令
stdin, stdout, stderr = ssh.exec_command('df')
# 获取命令结果
result = stdout.read()
print(result.decode('utf-8'))
# 关闭连接
ssh.close()

#上传下载
import paramiko

transport = paramiko.Transport(('123.56.157.199', 22022))
transport.connect(username='root', password='xxx')

sftp = paramiko.SFTPClient.from_transport(transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put(r'C:\\id_rsa', '/tmp/test.rsa') #必须写绝对路径
# 将remove_path 下载到本地 local_path
# sftp.get('remove_path', 'local_path')

transport.close()

相关文章

  • 第九篇 异常处理和并发编程1

    一、异常处理 二、基于udp协议的套接字通讯 三、udp协议不会粘包 Tcp和udp的区别Tcp协议是可靠的协议。...

  • Java并发编程 - 线程异常处理

    《Java编程思想》在讲到异常处理的时候有这样的一段话: Throwable这个Java类被用来表示任何可以作为异...

  • 2018-07-05学习

    1.认清自己 有一定的Java基础,但是对面向对象概念、集合的概念、io、多线程、并发、处理异常、Java网络编程...

  • Go 并发、Socket、HTTP 编程

    并发编程 1、并行和并发 并行(parallel): 指同一时刻,有多条指令在多个处理器上执行 并发(concur...

  • OC之并发编程

    1、什么是并发编程? 并发编程是指在一台处理器上“同时”处理多个任务。它的目标是充分的利用处理器的每一个核,以达到...

  • Python黑帽编程2.7 异常处理

    Python黑帽编程2.7 异常处理 Python黑帽编程2.7异常处理 异常是个很宽泛的概念,如果程序没有按预想...

  • [Erlang开发之路]十三、并发程序中的错误处理

    一、并发程序错误处理理念 Erlang并发编程中错误处理的概念,核心在于远程检测加处理错误(而非顺序编程中的避免错...

  • JMM内存模型简介

    1.并发编程模型的两个关键问题 并发编程中需要处理两个关键问题:线程之间如何通信和线程之间如何同步。通信是指线程之...

  • Go 语言学习笔记-并发编程

    Go 并发编程 概述 简而言之,所谓并发编程是指在一台处理器上“同时”处理多个任务。 宏观的并发:是指在一段时间内...

  • Java集合(二)

    1. List集合简单使用 2. 并发修改异常产生的原因和处理 3. 简单学习ListIterator(了解反向遍...

网友评论

      本文标题:第九篇 异常处理和并发编程1

      本文链接:https://www.haomeiwen.com/subject/qvwyeftx.html