# 服务端.py
import socketserver # 导入模块
# 先定义一个类,这个类专门解决通信循环的,必须继承一个类BaseRequestHandler
class MyRequestHandler(socketserver.BaseRequestHandler):
def handle(self): # 必须要写一个函数,叫handle的方法,里面放通信循环
while True:
try:
data = self.request.recv(1024) # 最大接收的字节数
if len(data) == 0:
break
print(data)
self.request.send(data.upper())
except Exception:
break
self.request.close()
# 链接循环,套接字属于IO密集型,对于IO密集型应该使用多线程
# 多线程ThreadingTCPServer里面放:监听的服务端ip和端口、定义的类、bind_and_activate=True
# bind_and_activate=True等同于bind()并且listen()默认属性为True无需添加。
server = socketserver.ThreadingTCPServer((‘127.0.0.1‘,8080),MyRequestHandler,bind_and_activate=True)
# 一直对外提供服务
server.serve_forever()
# serve_forever()每建成一个链接,都调用MyRequestHandler这个类,创建一个对象,
# 把它建成的链接对象赋值给self下面的request进行通信
# 整体逻辑:相当于客户端每发来一个请求,服务端就启一个线程,每启一个线程就去运行对象下面的
# handle方法,把跟这个客户端所有相关的套接字信息全都放到self对象里面去并触发这个对象下面
# 的handle方法用这个方法跟客户端进行通信
# 客户端.py (可实现多个客户端同时通信)
import socket
# 1、买手机
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 流式协议
# 2、打电话
phone.connect((‘127.0.0.1‘,8080))
# 3、发\收数据
while True:
msg = input(‘>>>: ‘).strip()
if len(msg) == 0:
continue
phone.send(msg.encode(‘utf-8‘))
data = phone.recv(1024)
print(data.decode(‘utf-8‘))
# 4、关闭
phone.close()
# 服务端.py
import socketserver
class MyRequesthanlder(socketserver.BaseRequestHandler):
# 必须要写一个函数,叫handle的方法,里面放通信循环
def handle(self):
# 收到消息,进行解压。第一个值是客户端发来的数据。第二个值是套接字对象,用它来回消息
data,server = self.request
# 将收到的消息转大写回复,所有套接字信息都封装进self里了
server.sendto(data.upper(),self.client_address)
server = socketserver.ThreadingUDPServer((‘127.0.0.1‘,9999),MyRequesthanlder)
server.serve_forever()
# 整体逻辑同上面TCP协议一样
# 客户端.py
from socket import *
client = socket(AF_INET,SOCK_DGRAM)
while True:
msg = input(">>>>:").strip()
client.sendto(msg.encode(‘utf-8‘),(‘127.0.0.1‘,9999))
res,server_addr = client.recvfrom(1024)
print(res.decode(‘utf-8‘))
操作系统位于计算机硬件与应用软件之间,本质也是一个软件。操作系统由操作系统的内核(运行于内核态,管理硬件资源)以及系统调用(运行于用户态,为应用程序员写的应用程序提供系统调用接口)两部分组成,所以,单纯的说操作系统是运行于内核态的,是不准确的
一 操作系统的作用:
1:隐藏丑陋复杂的硬件接口,提供良好的抽象接口
2:管理、调度进程,并且将多个进程对硬件的竞争变得有序
二 多道技术:
1.产生背景:针对单核,实现并发
ps:
现在的主机一般是多核,那么每个核都会利用多道技术
有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,会被调度到4个
cpu中的任意一个,具体由操作系统调度算法决定。
2.空间上的复用:如内存中同时有多道程序
3.时间上的复用:复用一个cpu的时间片
强调:遇到io切,占用cpu时间过长也切,核心在于切之前将进程的状态保存下来,这样
才能保证下次切换回来时,能基于上次切走的位置继续运行
进程也可以说成是操作系统干活的过程,
一个进程说白了就是操作系统控制硬件来运行应用程序的过程
所以说进程是操作系统最核心的概念,没有之一,研究进程就是在研究操作系统
单核下,可以利用多道技术,多个核,每个核也都可以利用多道技术(多道技术是针对单核而言的)
有四个核,六个任务,这样同一时间有四个任务被执行,假设分别被分配给了cpu1,cpu2,cpu3,
cpu4
一旦任务1遇到I/O就被迫中断执行,此时任务5就拿到cpu1的时间片去执行,这就是单核下的多道技术
而一旦任务1的I/O结束了,操作系统会重新调用它(需知进程的调度、分配给哪个cpu运行,由操作系统说了算),可能被分配给四个cpu中的任意一个去执行
所有现代计算机经常会在同一时间做很多件事,一个用户的PC(无论是单cpu还是多cpu),都可以同时运行多个任务(一个任务可以理解为一个进程)。
启动一个进程来杀毒(360软件)
启动一个进程来看电影(暴风影音)
启动一个进程来聊天(腾讯QQ)
所有的这些进程都需被管理,于是一个支持多进程的多道程序系统是至关重要的
多道技术概念回顾:内存中同时存入多道(多个)程序,cpu从一个进程快速切换到另外一个,使每个进程各自运行几十或几百毫秒,这样,虽然在某一个瞬间,一个cpu只能执行一个任务,但在1秒内,cpu却可以运行多个进程,这就给人产生了并行的错觉,即伪并发,以此来区分多处理器操作系统的真正硬件并行(多个cpu共享同一个物理内存)
①就绪→运行处于就绪状态的进程,当进程调度程序为之分配任务后,该进程便由就绪状态转变成运行状态。
②运行→就绪处于执行状态的进程在其执行过程中,因调度程序选择另一个进程,于是进程从执行状态转变成就绪状态。
③运行→阻塞正在运行的进程因等待某种事件发生而无法继续执行时,便从运行状态变成阻塞状态。
④阻塞→就绪处于阻塞状态的进程,若其等待的事件已经发生,于是进程由阻塞状态转变为就绪状态。
同步与异步针对的是函数/任务的调用方式:同步就是当一个进程发起一个函数(任务)调用的时候,一直等到函数(任务)完成,而进程继续处于激活状态。而异步情况下是当一个进程发起一个函数(任务)调用的时候,不会等函数返回,而是继续往下执行当,函数返回的时候通过状态、通知、事件等方式通知进程任务完成。
阻塞与非阻塞针对的是进程或线程:阻塞是当请求不能满足的时候就将进程挂起,而非阻塞则不会阻塞当前进程
进程是操作系统的概念,进程是由操作系统来开启的,例如你告诉操作系统有一段代码需要运行,把这段代码交给操作系统,就是一个进程。应用程序要开启进程,是为了实现多个任务的并发,真正能开启进程,管理进程的是操作系统。开启进程就是在给操作系统发起系统调用。调用的是操作系统的接口,而接口在Windows系统和Linux系统上是不一样的(Windows是CreateProcess,Linux是Fork),不同操作系统接口不同很正常,我们只需调用封装好的模块就可以,这个模块解决了跨平台性问题。
python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程。Python提供了multiprocessing。 multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似。
multiprocessing模块的功能众多:支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。
创建进程的类:
由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)
Process([group [, target [, name [, args [, kwargs]]]]])
强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
参数介绍:
group 参数未使用,值始终为None
target 表示调用对象,即子进程要执行的任务
args 表示调用对象的位置参数元组,args=(1,2,‘egon‘,)
kwargs 表示调用对象的字典,kwargs={‘name‘:‘egon‘,‘age‘:18}
name 为子进程的名称
方法介绍:
p.start():启动进程,并调用该子进程中的p.run()
p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,
使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive():如果p仍然运行,返回True
p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是
可选的 超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
属性介绍:
p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,
并且 设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
p.name:进程的名称
p.pid:进程的pid
p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网
注意:在windows中Process()必须放到# if name == ‘main‘:下
开启进程的方式一:可以让多个任务并发起来在后台同时运行
from multiprocessing import Process
import os
import time
def task(n):
print(‘父进程:%s 自己:%s 正在运行‘ %(os.getppid(),os.getpid()))
time.sleep(n)
print(‘父进程:%s 自己:%s 正在运行‘ % (os.getppid(), os.getpid()))
if __name__ == ‘__main__‘: # Windows规定启进程的代码必须放在它下面
# target表示调用对象,即子进程要执行的任务 ,args表示调用对象的位置参数元组
p = Process(target=task,args=(3,))
p.start() # 通知操作系统开启进程
print(‘主‘,os.getpid())
开启进程的方式二:用自定义类的方式(效果同方式一样)
from multiprocessing import Process
import os
import time
class Myprocess(Process): # 自定义的类必须继承Process类
def __init__(self,n):
super().__init__()
self.n = n
def run(self)->None:
print(‘父进程:%s 自己:%s 正在运行‘ % (os.getppid(),os.getpid()))
time.sleep(self.n)
print(‘父进程:%s 自己:%s 正在运行‘ % (os.getppid(), os.getpid()))
if __name__ == ‘__main__‘:
p = Myprocess(3)
p.start()
print(‘主‘,os.getpid())
from multiprocessing import Process
import time
count = 100 # 在windows系统中把全局变量定义在if __name__ == ‘__main__‘之上就可以了
def task():
global count
count = 0
if __name__ == ‘__main__‘:
p = Process(target=task)
p.start() # 通知操作系统开启进程
time.sleep(5) # 5秒够子进程启动起来运行完
print("主",count)
# 运行count = 100产生一个变量,定义一个函数,主进程里面有一份,然后开了一个子进程
# 开子进程的时候操作系统会把父进程数据一模一样复制给一份子进程,所以子进程也有100的值,
# 接着子进程启动的时候会运行task(),task()会将100改为0了,运行之后子进程改成功了,
# 那主进程呢?主进程的100仍然等于100,证明进程之间内存空间是彼此隔离的
# 例1:
from multiprocessing import Process
import os
import time
count = 100
def task():
global count
count = 0
if __name__ == ‘__main__‘:
p = Process(target=task)
p.start() # 通知操作系统开启进程
p.join() # 主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)
print("主",count)
# 例2:
from multiprocessing import Process
import os
import time
def task(n):
print(os.getpid())
time.sleep(n)
if __name__ == ‘__main__‘:
p1 = Process(target=task,args=(3,))
p2 = Process(target=task,args=(2,))
p3 = Process(target=task,args=(1,))
start = time.time()
p1.start() # 通知操作系统开启进程
p1.join()
p2.start() # 通知操作系统开启进程
p2.join()
p3.start() # 通知操作系统开启进程
p3.join()
stop = time.time()
print(stop - start)
# 加上join并不是变成串行了,而是看join放在什么位置,join往后放看到的是并发
# 例3:
from multiprocessing import Process
import os
import time
def task(n):
print(os.getpid())
time.sleep(n)
if __name__ == ‘__main__‘:
p1 = Process(target=task, args=(3,),name=‘进程1‘)
p1.start()
print(p1.name,p1.pid)
# p1.join()
p1.terminate()
time.sleep(0.01)
print(p1.is_alive())
原文:https://www.cnblogs.com/kk942260238/p/14302896.html