线程通信

通信方法:多个线程共用进程空间,所以进程的全局变量对进程内线程均可见。线程往往使用全局变量进行通信

注意事项:线程间使用全局变量进行通信,全局变量为共享资源,往往需要同步互斥机制

线程的同步互斥

线程Event

e = threading.Event()  创建事件对象

e.wait([timeout])  事件阻塞函数

e.set()  设置事件
e.clear()  清除事件

 from threading import Thread
 from time import sleep 

 a = 1

 def foo():
     global a
     a = 1000

 def bar():
     sleep(1)
     print("a = ",a)

 t1 = Thread(target = foo)
 t2 = Thread(target = bar)

 t1.start()
 t2.start()

 t1.join()
 t2.join()

 # a =  1000

thread_global

 import threading
 from time import sleep 

 s = None    #共享资源

 e = threading.Event()   #创建事件对象

 def bar():
     print("呼叫foo")
     global s
     s = "天王盖地虎"

 def foo():
     print("等口令")
     sleep(2)
     if s == "天王盖地虎":
         print("宝塔镇河妖")
     else:
         print("打死他")
     e.set() # 设置事件

 def fun():
     print("呵呵....")
     sleep(1)
     e.wait()    # 事件阻塞函数
     global s
     s = "小鸡炖蘑菇"

 b = threading.Thread(target = bar)  # 创建事件对象
 f = threading.Thread(target = foo)
 t = threading.Thread(target = fun)

 b.start()
 f.start()
 t.start()

 b.join()
 f.join()
 t.join()

 # 呼叫foo
 # 等口令
 # 呵呵....
 # 宝塔镇河妖

e = threading.Event()

线程锁 Lock

lock = threading.Lock() 创建锁对象
lock.acquire() 上锁
lock.release() 解锁

with lock 上锁

 import threading 

 a = b = 0 

 lock = threading.Lock()    # 创建锁对象

 def value():
     while True:
         lock.acquire()    # 上锁
         if a != b:
             print("a = %d,b = %d"%(a,b))
         lock.release()    # 解锁

 t = threading.Thread(target = value)    # 创建线程对象
 t.start()

 while True:
     lock.acquire()    # 上锁
     a += 1
     b += 1
     lock.release()    # 解锁

 t.join()

lock.acquire()

python线程的GIL问题

GIL (全局解释器锁)

python ---》 支持线程操作 ---》IO的同步和互斥 --》 加锁 ----》 超级锁,给解释器加锁

后果:一个解释器,同一时刻只解释一个线程,此时其他线程需要等待。大大降低了python线程的执行效率

python GIL问题解决方案
* 修改c解释器
* 尽量使用多进程进行并行操作
* python线程可以用在高延迟多阻塞的IO情形
* 不使用cpython  c# java做解释器

效率测试

分别测试 多进程 多线程 单进程执行相同的IO操作和CPU

 #计算密集
 def count(x,y):
     c = 0
     while c < 7000000:
         x += 1
         y += 1
         c += 1

 #io密集
 def write():
     f = open("test.txt",'w')
     for x in range(2000000):
         f.write("hello world\n")
     f.close()

 def read():
     f = open("test.txt")
     lines = f.readlines()
     f.close()

操作的时间

 #单进程程序
 from test import *
 import time 

 # t = time.time()
 # for i in range(10):
 #     count(1,1)
 # print("Line cpu:",time.time() - t)

 t = time.time()
 for i in range(10):
     write()
     read()
 print("Line IO:",time.time() - t)

Line cpu: 8.15166711807251
Line IO: 6.841825246810913

 from test import *
 import threading
 import time 

 counts = []

 t = time.time()

 for x in range(10):
     th = threading.Thread(target = count,args = (1,1))
     th.start()
     counts.append(th)

 for i in counts:
     i.join()
 print("Thread cpu",time.time() - t)
 from test import *
 import threading
 import time 

 counts = []

 def io():
     write()
     read()

 t = time.time()

 for x in range(10):
     th = threading.Thread(target = io)
     th.start()
     counts.append(th)

 for i in counts:
     i.join()
 print("Thread IO",time.time() - t)

Thread cpu 8.414522647857666
Thread IO 6.023292541503906

 from test import *
 import multiprocessing
 import time 

 counts = []

 t = time.time()

 for x in range(10):
     th = multiprocessing.Process\
     (target = count,args = (1,1))
     th.start()
     counts.append(th)

 for i in counts:
     i.join()
 print("Process cpu",time.time() - t)
 from test import *
 import multiprocessing
 import time 

 counts = []

 def io():
     write()
     read()

 t = time.time()

 for x in range(10):
     th = multiprocessing.Process(target = io)
     th.start()
     counts.append(th)

 for i in counts:
     i.join()
 print("Process IO",time.time() - t)

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. 客户端退出,对应子进程结束

 from socket import *
 import os,signal,sys,time  

 FILE_PATH = "/home/tarena/"    #文件库
 class TftpServer(object):    #实现功能模块
     pass 

 #流程控制,创建套接字,创建并发,方法调用
 def main():
     HOST = '0.0.0.0'
     PORT = 8888
     ADDR = (HOST,PORT)

     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("服务器退出")
         except Exception as e:
             print(e)
             continue
         print("客户端登录:",addr)

         #创建父子进程
         pid = os.fork()    # 子进程处理客户端请求,父进程等待其他客户端连接

         if pid == 0:
             sockfd.close()
             tftp = TftpServer()  # __init__传参
             while True:
                 data = connfd.recv(1024).decode()
                 if data == "list":
                     tftp.do_list()
                 elif data == 'get':
                     tftp.do_get()
                 elif data == 'put':
                     tftp.do_put()
                 elif data == 'quit':
                     print("客户端退出")
                     sys.exit(0)
         else:
             connfd.close()
             continue

 if __name__ == "__main__":
     main()

tftp_server

 from socket import *
 import sys
 import time 

 class TftpClient(object):    #实现各种功能请求
     pass
 #创建套接字建立连接
 def main():
     if len(sys.argv) < 3:
         print("argv is error")
         return
     HOST = sys.argv[1]
     PORT = int(sys.argv[2])
     ADDR = (HOST,PORT)

     sockfd = socket()
     sockfd.connect(ADDR)

     tftp = TftpClient()   #__init__是否需要传参

     while True:
         print("打印界面")

         cmd = input("输入命令>>")

         if cmd == "list":
             tftp.do_list()

 if __name__ == "__main__":
     main()

tftp_client

tftp 文件服务器

项目功能 :

* 客户端有简单的页面命令提示
* 功能包含:
1. 查看服务器文件库中的文件列表(普通文件)
2. 可以下载其中的某个文件到本地
3. 可以上传客户端文件到服务器文件库

* 服务器需求 :1. 允许多个客户端同时操作
2.每个客户端可能回连续发送命令

技术分析:
1. tcp套接字更适合文件传输
2. 并发方案 ---》 fork 多进程并发
3. 对文件的读写操作
4. 获取文件列表 ----》 os.listdir()
粘包的处理

整体结构设计
1. 服务器功能封装在类中(上传,下载,查看列表)
2. 创建套接字,流程函数调用 main()
3. 客户端负责发起请求,接受回复,展示
服务端负责接受请求,逻辑处理

pythonNet08的更多相关文章

  1. python学习菜单

    一.python简介 二.python字符串 三.列表 四.集合.元组.字典 五.函数 六.python 模块 七.python 高阶函数 八.python 装饰器 九.python 迭代器与生成器  ...

随机推荐

  1. python 列表嵌套

    >>> a = ['a', 'b', 'c'] >>> n = [, , ] >>> x = [a, n] >>> x [[, ...

  2. Nginx 正则匹配

    目录 Nginx 正则表达式之匹配操作符 过期缓存 针对浏览器 针对文件类型 针对文件夹 判断文件,文件夹 设置某些类型文件的浏览器缓存时间 匹配到所有uri 全局变量 常用正则 Nginx 正则表达 ...

  3. SpringBoot创建多模块方式以及打包方式

    springboot重构多模块的步骤 模型层:model 持久层:persistence 表示层:web 步骤: 正常创建一个springboot项目 修改创建项目的pom文件,将jar修改为pom ...

  4. Java IO流-字节流

    2017-11-05 17:48:17 Java中的IO流按数据类型分类分为两种,一是字节流,二是字符流.字符流的出现是为了简化文本数据的读入和写出操作. 如果操作的文件是文本文件,那么使用字符流会大 ...

  5. 对于应用之间的调用,如何选择rpc还是mq?

    两个系统之间的调用,是选择rpc呢还是mq,说一下你们系统的选择吧 比如rpc可以是简单的spring httpinvoker,但是前提是都是java应用而且都是用spring framework,可 ...

  6. [图床神器]Windows下的图片上传工具MPic

    最近用hexo在github上搭建了一个静态博客,开始几天用起来感觉还挺好的,但是用了些天就觉得每次写文章插入图片就非常麻烦,而且如果图片多了的话上传和访问就很慢了.后来网上看了下发现mac下有款ip ...

  7. BZOJ3288 Mato矩阵

    网上说高斯消元得到下三角矩阵然后都是phi(i)...反着我是搞不出来 打个表什么的还是能看出来点奇怪的东西,比如后面能整除前面的,然后再乱搞吧2333 /********************** ...

  8. C语言中的可变参数函数

    C语言编程中有时会遇到一些参数个数可变的函数,例如printf()函数,其函数原型为: int printf( const char* format, ...); 它除了有一个参数format固定以外 ...

  9. Centos系统更改yum源为163

    Centos安装好之后,按照网上教程对yum源进行修改,但更新之后发现总是提示更新失败,到163网站上查找资源发现目前大部分网上的教程都写错地址了,呵呵 下面是正确的办法,请参考 1.进入存放源配置的 ...

  10. springmvc的表单标签

    1. Spring提供的轻量级标签库 2.可在JSP页面中渲染HTML元素的标签 3 用法 1)必须在JSP页面的开头处声明taglib指令 <%@ taglib prefix="fm ...