线程通信
通信方法:多个线程共用进程空间,所以进程的全局变量对进程内线程均可见。线程往往使用全局变量进行通信
注意事项:线程间使用全局变量进行通信,全局变量为共享资源,往往需要同步互斥机制
线程的同步互斥
线程Event
e = threading.Event() 创建事件对象
e.wait([timeout]) 事件阻塞函数
e.set() 设置事件
e.clear() 清除事件


1 from threading import Thread 2 from time import sleep 3 4 a = 1 5 6 def foo(): 7 global a 8 a = 1000 9 10 def bar(): 11 sleep(1) 12 print("a = ",a) 13 14 t1 = Thread(target = foo) 15 t2 = Thread(target = bar) 16 17 t1.start() 18 t2.start() 19 20 t1.join() 21 t2.join() 22 23 # a = 1000
thread_global


1 import threading 2 from time import sleep 3 4 s = None #共享资源 5 6 e = threading.Event() #创建事件对象 7 8 def bar(): 9 print("呼叫foo") 10 global s 11 s = "天王盖地虎" 12 13 def foo(): 14 print("等口令") 15 sleep(2) 16 if s == "天王盖地虎": 17 print("宝塔镇河妖") 18 else: 19 print("打死他") 20 e.set() # 设置事件 21 22 def fun(): 23 print("呵呵....") 24 sleep(1) 25 e.wait() # 事件阻塞函数 26 global s 27 s = "小鸡炖蘑菇" 28 29 b = threading.Thread(target = bar) # 创建事件对象 30 f = threading.Thread(target = foo) 31 t = threading.Thread(target = fun) 32 33 b.start() 34 f.start() 35 t.start() 36 37 b.join() 38 f.join() 39 t.join() 40 41 # 呼叫foo 42 # 等口令 43 # 呵呵.... 44 # 宝塔镇河妖
e = threading.Event()
线程锁 Lock
lock = threading.Lock() 创建锁对象
lock.acquire() 上锁
lock.release() 解锁
with lock 上锁


1 import threading 2 3 a = b = 0 4 5 lock = threading.Lock() # 创建锁对象 6 7 def value(): 8 while True: 9 lock.acquire() # 上锁 10 if a != b: 11 print("a = %d,b = %d"%(a,b)) 12 lock.release() # 解锁 13 14 t = threading.Thread(target = value) # 创建线程对象 15 t.start() 16 17 while True: 18 lock.acquire() # 上锁 19 a += 1 20 b += 1 21 lock.release() # 解锁 22 23 t.join()
lock.acquire()
python线程的GIL问题
GIL (全局解释器锁)
python —》 支持线程操作 —》IO的同步和互斥 –》 加锁 —-》 超级锁,给解释器加锁
后果:一个解释器,同一时刻只解释一个线程,此时其他线程需要等待。大大降低了python线程的执行效率
python GIL问题解决方案
* 修改c解释器
* 尽量使用多进程进行并行操作
* python线程可以用在高延迟多阻塞的IO情形
* 不使用cpython c# java做解释器
效率测试
分别测试 多进程 多线程 单进程执行相同的IO操作和CPU


1 #计算密集 2 def count(x,y): 3 c = 0 4 while c < 7000000: 5 x += 1 6 y += 1 7 c += 1 8 9 #io密集 10 def write(): 11 f = open("test.txt",'w') 12 for x in range(2000000): 13 f.write("hello world\n") 14 f.close() 15 16 def read(): 17 f = open("test.txt") 18 lines = f.readlines() 19 f.close()
View Code
操作的时间


1 #单进程程序 2 from test import * 3 import time 4 5 # t = time.time() 6 # for i in range(10): 7 # count(1,1) 8 # print("Line cpu:",time.time() - t) 9 10 11 t = time.time() 12 for i in range(10): 13 write() 14 read() 15 print("Line IO:",time.time() - t)
View Code
Line cpu: 8.15166711807251
Line IO: 6.841825246810913


1 from test import * 2 import threading 3 import time 4 5 counts = [] 6 7 t = time.time() 8 9 for x in range(10): 10 th = threading.Thread(target = count,args = (1,1)) 11 th.start() 12 counts.append(th) 13 14 for i in counts: 15 i.join() 16 print("Thread cpu",time.time() - t)
View Code


1 from test import * 2 import threading 3 import time 4 5 counts = [] 6 7 def io(): 8 write() 9 read() 10 11 t = time.time() 12 13 for x in range(10): 14 th = threading.Thread(target = io) 15 th.start() 16 counts.append(th) 17 18 for i in counts: 19 i.join() 20 print("Thread IO",time.time() - t)
View Code
Thread cpu 8.414522647857666
Thread IO 6.023292541503906


1 from test import * 2 import multiprocessing 3 import time 4 5 counts = [] 6 7 t = time.time() 8 9 for x in range(10): 10 th = multiprocessing.Process\ 11 (target = count,args = (1,1)) 12 th.start() 13 counts.append(th) 14 15 for i in counts: 16 i.join() 17 print("Process cpu",time.time() - t)
View Code


1 from test import * 2 import multiprocessing 3 import time 4 5 counts = [] 6 7 def io(): 8 write() 9 read() 10 11 t = time.time() 12 13 for x in range(10): 14 th = multiprocessing.Process(target = io) 15 th.start() 16 counts.append(th) 17 18 for i in counts: 19 i.join() 20 print("Process IO",time.time() - t)
View Code
Process cpu 4.079084157943726
Process IO 3.2132551670074463
进程和线程的区别和联系
1.两者都是多任务编程的方式,都能够使用计算机的多核
2.进程的创建删除要比线程消耗更多的计算机资源
3.进程空间独立,数据安全性好,有专门的进程间通信方法
4.线程使用全局变量通信,更加简单,但是需要同步互斥操 作
5. 一个进程可以包含多个线程,线程共享进程的空间资源
6. 进程线程都独立执行,有自己的特有资源如属性,id, 命令集等
使用情况:
* 一个进程中并发任务比较多,比较简单,适合使用多线程
* 如果数据程序比较复杂,特别是可能多个任务通信比较多 的时候,要考虑到使用线程同步互斥的复杂性
* 多个任务存在明显差异,和功能分离的时候没有必要一定 写入到一个进程中
* 使用python考虑线程GIL问题
要求:
1. 进程线程的区别和关系
2. 进程间都信方式都用过哪些,有什么特点
3. 同步和互斥是怎么回事,你都用哪些方法实现了同步互斥
4. 什么是僵尸进程,怎么处理的
5. python线程的效率怎么样?GIL是怎么处理的
服务器模型
硬件服务器 : 主机 集群
厂商 : IBM HP 联想 浪潮
软件服务器 :编写的服务端程序,依托硬件服务器运行。 提供给用户一定的功能服务
服务器种类
webserver —》 网络的后端应用程序,提供数据处理和逻辑处理
httpserver —> 接受http请求,返回http响应
邮箱服务器 —》 处理邮件请求,进行邮件收发
文件服务器 –》提供文件的上传下载存储
功能实现 : 网络连接,逻辑处理,数据运算,数据交互
协议实现,网络数据传输。。。。
模型结构 : C/S 客户端服务器模型
B/S 浏览器服务器模型
服务器目标:处理速度更快,数据安全性更强,并发量更高
硬件 : 更高的配置,更好的硬件搭配,更高的网络速度
更多的主机,网络安全投入
软件:占有更少的计算机资源,更稳定的运行效率,更流畅的速度,更强大的算法,更合理的技术搭配
网络服务器基础
循环服务器 : 单进程程序,循环接受客户请求,处理请求。处理完毕再接受下一个请求。
特点 : 每次只能处理一个客户端请求;如果客户端长期占有服务器则无法处理其他客户端请求。
优点 : 实现简单,占用资源少
缺点 : 无法同时处理多客户端,体验差
使用情况 : 任务短暂,可以快速完成。udp比tcp更适合循 环
并发服务器 : 能够同时处理多个客户端任务请求
IO 并发 : IO多路复用 协程
优点 : 可以实现IO的并发操作,占用系统资源少
缺点 : 不能监控cpu密集的情况,并能有长期阻塞
多进程/多线程并发:为每个客户端单独提供一个进程/ 线程处理客户端请求
优点 : 客户端可以长期占有服务器
缺点 : 消耗计算机资源较多
多进程并发模型
使用fork完成并发
1. 创建套接字,绑定,监听
2. 等待接受客户端连接请求
3. 创建新的进程处理客户端请求,父进程继续等待连接其他客户端
4. 客户端退出,对应子进程结束


1 from socket import * 2 import os,signal,sys,time 3 4 FILE_PATH = "/home/tarena/" #文件库 5 class TftpServer(object): #实现功能模块 6 pass 7 8 #流程控制,创建套接字,创建并发,方法调用 9 def main(): 10 HOST = '0.0.0.0' 11 PORT = 8888 12 ADDR = (HOST,PORT) 13 14 sockfd = socket() 15 sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) 16 sockfd.bind(ADDR) 17 sockfd.listen(5) 18 19 signal.signal(signal.SIGCHLD,signal.SIG_IGN) 20 21 while True: 22 try: 23 connfd,addr = sockfd.accept() 24 except KeyboardInterrupt: 25 sockfd.close() 26 sys.exit("服务器退出") 27 except Exception as e: 28 print(e) 29 continue 30 print("客户端登录:",addr) 31 32 #创建父子进程 33 pid = os.fork() # 子进程处理客户端请求,父进程等待其他客户端连接 34 35 if pid == 0: 36 sockfd.close() 37 tftp = TftpServer() # __init__传参 38 while True: 39 data = connfd.recv(1024).decode() 40 if data == "list": 41 tftp.do_list() 42 elif data == 'get': 43 tftp.do_get() 44 elif data == 'put': 45 tftp.do_put() 46 elif data == 'quit': 47 print("客户端退出") 48 sys.exit(0) 49 else: 50 connfd.close() 51 continue 52 53 if __name__ == "__main__": 54 main()
tftp_server


1 from socket import * 2 import sys 3 import time 4 5 class TftpClient(object): #实现各种功能请求 6 pass 7 #创建套接字建立连接 8 def main(): 9 if len(sys.argv) < 3: 10 print("argv is error") 11 return 12 HOST = sys.argv[1] 13 PORT = int(sys.argv[2]) 14 ADDR = (HOST,PORT) 15 16 sockfd = socket() 17 sockfd.connect(ADDR) 18 19 tftp = TftpClient() #__init__是否需要传参 20 21 while True: 22 print("打印界面") 23 24 cmd = input("输入命令>>") 25 26 if cmd == "list": 27 tftp.do_list() 28 29 if __name__ == "__main__": 30 main()
tftp_client
tftp 文件服务器
项目功能 :
* 客户端有简单的页面命令提示
* 功能包含:
1. 查看服务器文件库中的文件列表(普通文件)
2. 可以下载其中的某个文件到本地
3. 可以上传客户端文件到服务器文件库
* 服务器需求 :1. 允许多个客户端同时操作
2.每个客户端可能回连续发送命令
技术分析:
1. tcp套接字更适合文件传输
2. 并发方案 —》 fork 多进程并发
3. 对文件的读写操作
4. 获取文件列表 —-》 os.listdir()
粘包的处理
整体结构设计
1. 服务器功能封装在类中(上传,下载,查看列表)
2. 创建套接字,流程函数调用 main()
3. 客户端负责发起请求,接受回复,展示
服务端负责接受请求,逻辑处理
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/159325.html