socket
最底层的网络通信,所有的网络通信都是基于socket
什么是进程
在操作系统发展的过程中,为了提高cpu的利用率,在操作系统同时运行多个程序的时候,为了数据安全、代码不混乱而被创造出来的一个概念,每一个程序运行起来都至少是一个进程。进程是计算机中最小的资源分配单位,进程是被操作系统调度的,有很多相关的算法,进程之间是数据隔离的
进程的三状态
就绪、运行、阻塞
同步异步
同步:一个任务的执行依赖于另一个任务的结束
异步:一个任务的执行不依赖于另一个任务的结束
阻塞与非阻塞
阻塞:accept、recv、recvfrom、queue.get、join
非阻塞:setblocking = False
并发与并行
并行是特殊的并发
并行就是同一时刻两个以上的 程序同时在cpu上执行
并发就是同一时段两个以上的程序看起来在同时运行
IO概念:文件操作、数据库操作、网络传输、用户输入输出
Input 等到bytes、str
Output 发送数据、输出数据
因为进程与进程之间本质是异步的且数据隔离
主进程会等待子进程结束之后才结束,因为父进程负责创建子进程,也负责回收子进程的资源
p=Process(target = 子进程名,args = (给子进程传的参数,(以元组的形式传递)))
p.start() 开启子进程,异步的
p.is_alive() 查看子进程是否存活
p.terminate() 在主进程中结束子进程,异步的
global 子进程对主进程中的全局变量的修改是不生效的
p.join() 阻塞 直到子进程结束
p.join(timeout = 5) 设置超时 主进程阻塞5秒 如果子进程结束程序结束阻塞
如果超过5秒子进程还没有结束,那么也结束阻塞
p.daemon = True 设置子进程为守护进程,守护进程随着主代码的结束而结束
由于主进程负责回收子进程的资源,所以主进程必须最后结束,守护进程只能在主进程的代码结束之后就认为主进程结束了,不会等待其他子进程。
锁(lock(互斥锁))
lock.acquire() #第一个到达的程序拿到钥匙,其他程序在这里阻塞
lock.release() # 有程序还钥匙,下一个程序才能继续执行
为什么要用锁?
由于多个进程的并发,导致很多数据的操作都在同步执行
所以就会产生多个进程同时操作:文件、数据库中的数据,导致数据不安全,所以给某一段修改数据的程序加上锁,就可以控制文件、数据库永远不会同时被多个进程同时操作,从而保证了文件,数据的安全。
锁实际上是把你的某一段程序变成了同步的了,降低了程序的运行速度,为了保证数据的安全性
信号量(semaphore)(实质是一个类)
保证一段代码同一时刻只能被n个进程执行
import time
import random
from multiprocessing import Process,Semaphore
def ktv(name,sem):
sem.acquire() #拿钥匙
print('%s走进了ktv'%name)
time.sleep(random.randint(5,10))
print('%s走出了ktv'%name)
sem.release() #还钥匙
if __name__ == '__main__':
sem = Semaphore(4) #参数为钥匙个数(最多一次可以执行几个进程)
for i in range(100): #创建多个进程
p = Process(target = ktv,args = ('name%s'%i,sem))
p.start() #开启多个进程
事件(Event)(实质是一个类)
时间本身就带着标识:False
阻塞条件是 对象标识为False
结束阻塞的条件 对象标识为True
# import time
# import random
# from multiprocessing import Event,Process
# def traffic_light(e):
# print('\033[1;31m红灯亮\033[0m')
# while True:
# time.sleep(2)
# if e.is_set(): # 如果当前是绿灯
# print('\033[1;31m红灯亮\033[0m') # 先打印红灯亮
# e.clear() # 再把灯改成红色
# else : # 当前是红灯
# print('\033[1;32m绿灯亮\033[0m') # 先打印绿灯亮
# e.set() # 再把灯变绿色
#
# def car(e,carname):
# if not e.is_set():
# print('%s正在等待通过'%carname)
# e.wait()
# print('%s正在通过'%carname)
#
# if __name__ == '__main__':
# e = Event()
# p = Process(target=traffic_light,args = (e,))
# p.start()
# for i in range(100):
# time.sleep(random.randrange(0,3))
# p = Process(target=car, args=(e,'car%s'%i))
# p.start()
对象标识相关的:
set 将对象的标识设置为True
clear 将对象的标识设置为False
is_set 查看对象的标识是否为True
IPC #进程之间通信(Inter-Process Communication)
实现进程之间通信的两种机制:
管道 Pipe(实质是类)
队列 Queue(实质是类)
生产者与消费者模型
import time
from multiprocessing import Queue,Process
def producer(name,food,num,q):
'''生产者'''
for i in range(num):
time.sleep(0.3)
foodi = food + str(i)
print('%s生产了%s'%(name,foodi))
q.put(foodi) #传输数据给另一个子进程
def consumer(name,q):
while True:
food = q.get() # 等待接收数据
if food == None:break
print('%s吃了%s'%(name,food))
time.sleep(1)
if __name__ == '__main__':
q = Queue(maxsize=10)
p1 = Process(target=producer,args = ('宝元','泔水',20,q))
p2 = Process(target=producer,args = ('战山','鱼刺',10,q))
c1 = Process(target=consumer, args=('alex', q))
c2 = Process(target=consumer, args=('wusir', q))
p1.start() # 开始生产
p2.start() # 开始生产
c1.start()
c2.start()
p1.join() # 生产者结束生产了
p2.join() # 生产者结束生产了
q.put(None) # put None 操作永远放在所有的生产者结束生产之后
q.put(None) # 有几个消费者 就put多少个None
池(Pool)
from multiprocessing import Pool # 池
def func(i):
i -= 1
return i**2 #有返回值
if __name__ == '__main__':
p = Pool(5) # # 你的池中打算放多少个进程,个数cpu的个数 * 1|2
ret = p.map(func,range(100)) # 自动带join
print(ret)
有了进程池,不仅可以只开有限个进程来完成无限个任务还可以获取进程执行的返回值
# 同步方式向进程池提交任务
# import time
# from multiprocessing import Pool # 池
# def func(i):
# i -= 1
# time.sleep(0.5)
# return i**2
#
# # 你的池中打算放多少个进程,个数cpu的个数 * 1|2
# if __name__ == '__main__':
# p = Pool(5)
# for i in range(100):
# ret = p.apply(func,args=(i,)) # 自动带join 串行 同步 apply就是同步提交任务
# print(ret)
# 异步方式向进程池提交任务
# import time
# from multiprocessing import Pool # 池
# def func(i):
# i -= 1
# time.sleep(0.1)
# print(i)
# return i**2
#
# # 你的池中打算放多少个进程,个数cpu的个数 * 1|2
# if __name__ == '__main__':
# p = Pool(5)
# for i in range(100):
# ret = p.apply_async(func,args=(i,)) # 自动带join 异步的 apply_async异步提交任务
# p.close() # 关闭进程池的任务提交 从此之后不能再向p这个池提交新的任务
# p.join() # 阻塞 一直到所有的任务都执行完
# 异步方式向进程池提交任务并且获取返回值
# import time
# from multiprocessing import Pool # 池
# def func(i):
# i -= 1
# time.sleep(1)
# return i**2
#
# # 你的池中打算放多少个进程,个数cpu的个数 * 1|2
# if __name__ == '__main__':
# p = Pool(5)
# l = []
# for i in range(100):
# ret = p.apply_async(func,args=(i,)) # 自动带join 异步的 apply_async异步提交任务
# l.append(ret)
# for ret in l:
# print(ret.get())
# 向进程池中提交任务的三种方式
# map 异步提交任务 简便算法 接收的参数必须是 子进程要执行的func,可迭代的(可迭代中的每一项都会作为参数被传递给子进程)
# 能够传递的参数是有限的,所以比起apply_async限制性比较强
# apply 同步提交任务(你删了吧)
# apply_async 异步提交任务
# 能够传递比map更丰富的参数,但是比较麻烦
# 首先 apply_async提交的任务和主进程完全异步
# 可以通过先close进程池,再join进程池的方式,强制主进程等待进程池中任务的完成
# 也可以通过get获取返回值的方式,来等待任务的返回值
# 我们不能在apply_async提交任务之后直接get获取返回值
# for i in range(100):
# ret = p.apply_async(func,args=(i,)) # 自动带join 异步的 apply_async异步提交任务
# l.append(ret)
# for ret in l:
# print(ret.get())
# 回调函数
# import os
# import time
# import random
# from multiprocessing import Pool # 池
# def func(i): # [2,1,1,5,0,0.2]
# i -= 1
# time.sleep(random.uniform(0,2))
# return i**2
#
# def back_func(args):
# print(args,os.getpid())
#
# if __name__ == '__main__':
# print(os.getpid())
# p = Pool(5)
# l = []
# for i in range(100):
# ret = p.apply_async(func,args=(i,),callback=back_func) # 5个任务
# p.close()
# p.join()
# callback回调函数
# 主动执行func,然后在func执行完毕之后的返回值,直接传递给back_func作为参数,调用back_func
# 处理池中任务的返回值
# 回调函数是由谁执行的? 主进程
进程
对操作系统压力大
数据隔离
可以在操作系统中独立存在
计算机中资源分配的最小单位
线程(轻量级进程、轻型进程)
线程是计算机中被cpu调度的最小单位
线程本身就是为了解决并发问题,并且它的整体效率比进程高
在进程中数据共享,
在整个程序界
如果你的程序需要数据隔离: 多进程
如果你的进程对并发要求非常高: 多线程(socketserver就是多线程的)
对于python来说,同一时刻只能有一个线程被cpu访问,为了彻底解决多核环境的安全问题所以就有了线程锁
GIL 线程锁(全局解释器锁)(这个锁是解释器提供的)
Thread 线程类
import os
import time
from threading import Thread
def func():
print('start',os.getpid())
time.sleep(1)
print('end')
if __name__ '__main__':
t = Thread(target = func)
t.start()
for i in range(5):
print('主线程',os.getpid())
time.sleep(0.3)
开启另一个线程的另一种方式
from threading import Thread
class Mythread (Thread):
def __init__(self,arg):
super().__init__()
self.arg = arg
def run(self):
print('in son',self.arg)
t = Mythread(123)
t.start()
守护线程
import time
from threading import Thread
def func():
while True:
print('in func')
time.sleep(0.5)
def func2():
print('start func2')
time.sleep(10)
print('end func2')
Thread(target = func2).start()
t = Thread(target = func)
t.setDaemon(True)
t.start()
print('主线程')
time.sleep(2)
print('主线程')
守护进程只守护主进程的代码,主进程的代码结束了就结束守护,守护进程在主进程之前结束
守护线程 随着主线程的结束才结束
进程 terminate 强制结束一个进程
线程 没有强制结束的方法
线程结束:线程内部的代码执行完毕,自动结束