内核 ----》操作系统的核心代码
并发 : 同时处理多个请求,但是内核采用轮询时间片的方式逐个访问,某一时间点实际只处理一个任务。
比如 :IO多路复用 协程 循环服务器。单线程
并行 : 使用多个内核,同时执行多个任务
比如 : 多进程 多线程
计算机原理 算法导论
python程序员 python开发者
掘金
线程 threading.Thread
进程和线程的同步互斥
Event Lock
**********************************************
condition 条件变量
创建条件变量对象
con = threading.Condition()
con.acquire() : 对资源加锁,加锁后其他位置再加锁则阻塞
con.release() : 解锁
con.wait() : wait函数只能在 加锁的状态下使用。 wait函数会先解锁(release),然后让线程处于等待通知的阻塞状态
con.notify() : 发送通知,线程接收到通知后 结束wait阻塞,并且执行 acquire 加锁操作
threadpool 第三方模块
python线程之GIL
(全局解释器锁)
python ---》 支持多线程 ---》同步互斥 ---》加锁 ---》 超级锁 ----》 在同一时刻,解释器只能解释一个线程 -----》大量python库为了省事沿用了这种方法 ---》python 多线程效率低下
GIL 问题 : 由于python的全局解释器锁造成python的多线程执行效率低下
解决方法 :
* 不使用线程,使用多进程
* 不使用c c++ 做解释器 C# java
* python线程适合高用时的IO操作,网路IO。不适合cpu密集型程序
GIL带来的影响
单进程
Line cpu: 6.7326600551605225
Line IO: 3.783463478088379
多线程
Thread cpu 6.855324745178223
Thread IO 4.32829213142395
多进程
Process cpu 3.297400951385498
Process IO 1.6371185779571533
设计模式
设计模式代表了一种最佳实践,是被开发人员长期总结,用来解决某一类问题的思路方法。这些方法保证了代码的效率也已于理解
单例模式 工厂模式 生产者模式。。。。
生产者消费者
控制数据资源数量
降低耦合度
多个消费者 消耗
多个生产者 生产
均对仓库资源进行操作
总结:
1. 进程线程区别和联系
2. 同步互斥的意义和实现方法
3. 进程线程使用什么样的方式通信
4. 进程线程的特点和选择
5. 简单的设计模式的理解
6. 僵尸进程,进程状态, GIL等概念的理解
服务器模型
硬件服务器 : 主机 集群
IBM HP
软件服务器 : 网络服务器 在后端提供网络功能,逻辑处理,数据处理的程序或者架构等
例如 httpserver django flask
服务器架构 : c/s(客户端服务器)
b/s(浏览器服务器)
服务器的组织形式
服务器追求 : 处理速度快,数据更安全,并发量大
硬件 : 更高配置,更多主机,集成,分布
软件 : 程序占有更少的资源,更流畅的运行,处理更多的并发
基本的服务器模型
循环 并发模式 IO多路复用
循环 : 单线程程序 ,循环接收连接或者请求,然后处理,处理后继续循环
缺点 : 不能同时处理多个客户端的并行,不允许某个客户端长期占有服务器
结构比较简单,适用于UDP程序,要求处理请求可以很快完成
IO多路复用模型:通过同时监控多个IO 来达到IO并发的目的。
缺点 : 也是单线程,不能够长期阻塞。不适合处理大量cpu占有高的程序
开销小,比较适合IO密集型的服务端程序,
并行服务器: 每有一个客户端连接请求,就创建一个新的进程或者线程处理客户端的请求,而主进程/主线程可以继续接受其他客户端的连接
缺点 : 资源消耗比较大
客户端需要长期占有服务器的情况
基于fork的多进程并发
1.创建套接字 绑定 监听
2.接受客户端请求
3.创建子进程处理客户端请求,父进程继续准备接受新的客户端连接
4.客户端退出,销毁相应的子进程
TFTP文件服务器
文件的上传,下载,和服务端文件库的查看
服务端 客户端
1.查看文件库中有哪些文件
2.下载文件到本地
确定技术
fork --- 多进程
tcp socket
os.listdir(path)
获取该文件夹下所有文件,形成一个列表
os.path.isfile(path)
os.path.isdir(path)
判断一个文件是否是普通文件/文件夹
作业 : 完成tftp文件服务器 get 和 put功能
**********************************************************************
import threading
import time
import datetime
num = 0
#条件变量
con = threading.Condition()
class Gov(threading.Thread):
def run(self):
global num
con.acquire()
while True:
print("开始拉升股市")
num += 1
print("拉升到 %d 个点"%num)
time.sleep(2)
if num == 5:
print('暂时安全!')
con.notify()
print("不操作状态")
con.wait()
con.release()
class Consumers(threading.Thread):
def run(self):
global num
con.acquire()
while True:
if num > 0:
print("开始打压股市")
num -= 1
print("下降到%d个点"%num)
time.sleep(2)
if num == 0:
print("天台在哪")
con.notify()
print("不能在下降了")
con.wait()
con.release()
t1 = Gov()
t2 = Consumers()
t1.start()
t2.start()
**********************************************************************************
import multiprocessing as mp
from signal import *
import os
from time import sleep
def saler_handler(sig,frame):
if sig == SIGINT:
os.kill(os.getppid(),SIGUSR1)
elif sig == SIGQUIT:
os.kill(os.getppid(),SIGUSR2)
elif sig == SIGUSR1:
print("到站了,请下车")
os._exit(0)
def driver_handler(sig,frame):
if sig == SIGUSR1:
print("老司机,开车了")
elif sig == SIGUSR2:
print("车速有点快,系好安全带")
elif sig == SIGTSTP:
os.kill(p.pid,SIGUSR1)
#售票员
def saler():
signal(SIGINT,saler_handler)
signal(SIGQUIT,saler_handler)
signal(SIGUSR1,saler_handler)
signal(SIGTSTP,SIG_IGN)
while True:
sleep(2)
print("Python 带你去远方")
p = mp.Process(target = saler)
p.start()
signal(SIGUSR1,driver_handler)
signal(SIGUSR2,driver_handler)
signal(SIGTSTP,driver_handler)
signal(SIGINT,SIG_IGN)
signal(SIGQUIT,SIG_IGN)
p.join()
**********************************************************************************
from socket import *
import os,sys
import signal
#创建套接字
HOST = ""
PORT = 8888
def client_handler(c):
try:
print("子进程接受客户的请求",c.getpeername())
while True:
data = c.recv(1024).decode()
if not data:
break
print(data)
c.send(b"receive your message")
except (KeyboardInterrupt,SystemExit):
raise
except Exception as e:
print(e)
c.close()
sys.exit(0) # 结束子进程
s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind((HOST,PORT))
s.listen(5)
print("父进程 %d 等待客户端链接"%os.getpid())
while True:
try:
c,addr = s.accept()
except KeyboardInterrupt:
raise
except Exception as e:
print(e)
continue
#为新的客户端创建进程
#处理僵尸进程
signal.signal(signal.SIGCHLD,signal.SIG_IGN)
pid = os.fork()
if pid < 0:
print("创建子进程失败")
c.close()
continue
elif pid == 0:
s.close()
#处理客户端请求
client_handler(c)
else:
c.close()
continue
**********************************************************************************
from threading import Thread
#python标准库队列
import queue
from time import sleep
#创建一个队列作为仓库
q = queue.Queue()
#生产者
class Producer(Thread):
def run(self):
count = 0
while True:
if q.qsize() < 50:
for i in range(3):
count += 1
msg = "产品 %d"%count
q.put(msg) #将产品放入队列
sleep(1)
#消费者
class Customer(Thread):
def run(self):
while True:
if q.qsize() > 20:
for i in range(2):
msg = q.get() #从仓库拿货
print("消费了%s"%msg,\
"还有%d个"%q.qsize())
sleep(1)
#创建两个生产
for i in range(2):
p = Producer()
p.start()
#创建三个消费
for i in range(3):
c = Customer()
c.start()
**********************************************************************************
from socket import *
import sys
import time
#客户请求类
class TftpClient(object):
def __init__(self,sockfd):
self.sockfd = sockfd
def do_list(self):
self.sockfd.send(b'L') #发送请求类别
#服务器回复 Y / N
data = self.sockfd.recv(1024).decode()
if data == 'Y':
data = self.sockfd.recv(4096).decode()
files = data.split('#')
for file in files:
print(file)
print("文件列表展示完毕")
else:
print("请求文件列表失败")
def do_get(self,filename):
pass
def do_put(self,filename):
pass
def do_quit(self):
self.sockfd.send(b"Q")
self.sockfd.close()
sys.exit(0)
def main():
if len(sys.argv) < 3:
print("argv is error")
sys.exit(1)
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST,PORT)
BUFFERSIZE = 1024
sockfd = socket()
sockfd.connect(ADDR)
#创建客户请求对象
tftp = TftpClient(sockfd)
while True:
print("========命令选项========")
print("******** list **********")
print("******* get file *******")
print("******* put file *******")
print("******** quit **********")
print("========================")
data = input("输入命令>>")
if data.strip() == "list":
tftp.do_list()
elif data[:3] == "get":
filename = data.split(' ')[-1]
tftp.do_get(filename)
elif data[:3] == "put":
filename = data.split(' ')[-1]
tftp.do_put(filename)
elif data.strip() == "quit":
tftp.do_quit()
else:
print("请输入正确的命令!!!")
if __name__ == "__main__":
main()
**********************************************************************************
from socket import *
import os,sys
import signal
import time
#文件库位置
FILE_PATH = "/home/tarena/pythonweb/day3/"
class TftpServer(object):
def __init__(self,connfd):
self.connfd = connfd
def do_list(self):
filelist = os.listdir(FILE_PATH)
if not filelist:
self.connfd.send(b'N')
return
else:
self.connfd.send(b"Y")
time.sleep(0.1)
files = ""
for filename in filelist:
if filename[0] != '.' and os.path.isfile(FILE_PATH + filename):
files = files + filename + '#'
self.connfd.send(files.encode())
def do_get(self):
pass
def do_put(self):
pass
def main():
if len(sys.argv) < 3:
print("argv is error")
sys.exit(1)
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST,PORT)
BUFFERSIZE = 1024
sockfd = socket()
sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
sockfd.bind(ADDR)
sockfd.listen(5)
signal.signal(signal.SIGCHLD,signal.SIG_IGN)
while True:
try:
connfd,addr = sockfd.accept()
except KeyboardInterrupt:
sockfd.close()
sys.exit(0)
except Exception:
continue
print("客户登录:",addr)
pid = os.fork()
if pid < 0:
print("创建子进程失败")
connfd.close()
continue
elif pid == 0:
sockfd.close()
#创建客户端通信对象
tftp = TftpServer(connfd)
while True:
#接受客户端的请求类型
data = connfd.recv(BUFFERSIZE).decode()
if data[0] == 'L':
tftp.do_list()
elif data[0] == 'G':
tftp.do_get()
elif data[0] == "P":
tftp.do_put()
elif data[0] == "Q":
print("客户端退出")
sys.exit(0)
else:
connfd.close()
continue
if __name__ == "__main__":
main()
**********************************************************************************