线程通信

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

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

线程的同步互斥

线程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. HDU 3435 A new Graph Game(最小费用流:有向环权值最小覆盖)

    http://acm.hdu.edu.cn/showproblem.php?pid=3435 题意:有n个点和m条边,你可以删去任意条边,使得所有点在一个哈密顿路径上,路径的权值得最小. 思路: 费用 ...

  2. 基于Codis的Redis集群部署

    Codis是基于代理的高性能Redis集群方案,使用Go语言进行开发,现在在在豌豆荚及其它公司内已经广泛使用,当然也包括我们公司. Codis与常见的Redis集群方案对比. 在搭建的时候,个人觉得R ...

  3. php多站点配置以及Forbidden You don't have permission to access / on this server问题解决

    php多站点配置以及Forbidden You don't have permission to access / on this server问题解决 一.总结 一句话总结:我的问题是php的版本问 ...

  4. git 设置 代理服务器

    git config --global http.proxy http://proxyuser:proxypwd@proxy.server.com:8080 git config --global h ...

  5. 何时使用MQ ?

    何时使用MQmq作为一种基础中间件在互联网项目中有着大量的使用. 一种技术的产生自然是为了解决某种需求,通常来说是以下场景: 需要跨进程通信:B系统需要A系统的输出作为输入参数.当A系统的输出能力远远 ...

  6. devdocs

    https://devdocs.io/ docker run --rm -d --name devdocs -p 9292:9292 devdocs/devdocs

  7. c++运算符优先级表

    优先级 操作符 描述 例子 结合性 1 () [] -> . :: ++ -- 调节优先级的括号操作符 数组下标访问操作符 通过指向对象的指针访问成员的操作符 通过对象本身访问成员的操作符 作用 ...

  8. 尝试读取或写入受保护的内存。这通常指示其他内存已损坏。(System.Data)

    Sql server2012连接Sql server2008时出现的问题:已成功与服务器建立连接,但在登陆过程中发生错误.(provider:SSLProvider,error:0-接收到的消息异常, ...

  9. Python3 内建函数一览

    ###################################################### """Python3 内建函数大全""& ...

  10. 《免费前端教程不会告诉你这些》知乎LIVE读后感

    这个是昨天偶然间在知乎上看到的一个知乎LIVE,答题就是音频在线直播吧,我试听了一下觉得分享的还不错,就买了完整的.主讲人叫方应杭,貌似是个挺牛逼的程序猿,之前没有听过,但这是个典型的科班出生的程序员 ...