python-day18
1、线程、
线程共享的不安全性
''' 线程共享数据的不安全性 ''' import time from threading import Thread, current_thread, Lock ticket = 10 def sale_ticket(lock): global ticket while True: if ticket > 0: lock.acquire() print('{}正在卖第{}张票'.format(current_thread().name, ticket)) ticket -= 1 lock.release() time.sleep(1) else: print('票卖光啦!') # lock.release() break if __name__ == '__main__': lock = Lock() t1 = Thread(target=sale_ticket, name='1号窗口', args=(lock,)) t2 = Thread(target=sale_ticket, name='2号窗口', args=(lock,)) t3 = Thread(target=sale_ticket, name='3号窗口', args=(lock,)) t4 = Thread(target=sale_ticket, name='4号窗口', args=(lock,)) t4.start() t1.start() t2.start() t3.start()
死锁:两把锁
申请锁的顺序使用不当
开发过程中使用线程,在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,尽管死锁很少发生,但一旦发生就会造成应用的停止响应,程序不做任何事情
避免死锁:
1、重构代码 2、使用timeout参数
import time from threading import Lock, Thread, current_thread def task1(lock1, lock2): if lock1.acquire(): print('{}获取到lock1锁。。。。'.format(current_thread().name)) for i in range(5): print('{}------------------>{}'.format(current_thread().name, i)) time.sleep(0.01) if lock2.acquire(timeout=2): print('{}获取了lock1,lock2'.format(current_thread().name)) lock2.release() lock1.release() def task2(lock1, lock2): if lock2.acquire(): print('{}获取到lock2锁。。。。'.format(current_thread().name)) for i in range(5): print('{}----->{}'.format(current_thread().name, i)) time.sleep(0.01) if lock1.acquire(timeout=2): print('{}获取了lock1,lock2'.format(current_thread().name)) lock1.release() lock2.release() if __name__ == '__main__': lock1 = Lock() lock2 = Lock() t1 = Thread(target=task1, args=(lock1, lock2)) t2 = Thread(target=task2, args=(lock1, lock2)) t1.start() t2.start()
线程同步:
同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。
"同"字从字面上容易理解为一起动作
其实不是,"同"字应是指协同、协助、互相配合。
如进程、线程同步,可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给A;A再继续操作。
线程异步:
在没有共享数据的情况下使用,效率高
进程线程的区别:
定义的不同
进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
区别
一个程序至少有一个进程,一个进程至少有一个线程.
线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
线线程不能够独立执行,必须依存在进程中
优缺点
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。
2、线程的信号量
信号量的实现方式:
在内部有一个counter计数器,每当我们 s.acquire()一次,计数器就进行减1处理
每当 s.release()一次,计数器就进行加1处理,当计数器为0的时候其他线程的就处于
等待的状态counter的值就是同一时间可以开启线程的个数
建议使用with
import time from threading import Thread, Semaphore, current_thread # from multiprocessing import Semaphore,Process def task(s): s.acquire() # 减1 with s: for i in range(5): print('{}扫地....{}'.format(current_thread().name, i)) time.sleep(1) s.release() # 加1 if __name__ == '__main__': s = Semaphore(4) for i in range(10): t = Thread(target=task, args=(s,)) t.start()
3、协程:伪线程
实现交替执行
def eat(): for i in range(5): print('gang welcome you') yield def listen(): for i in range(5): print('yinxing de chi bang') yield if __name__ == '__main__': a1 = eat() a2 = listen() while True: try: next(a1) next(a2) except: break
gevent:使用猴子补丁实现交替执行(给耗时的操作贴上标签)
import time import gevent from gevent import monkey monkey.patch_all() def eat(): for i in range(5): print('gang welcome you') time.sleep(0.1) def listen(): for i in range(5): print('yinxing de chi bang') time.sleep(0.1) if __name__ == '__main__': g1 = gevent.spawn(eat) g2 = gevent.spawn(listen) g1.join() g2.join() print('over...')
网络编程
端口号:理解成端口号,识别应用
netstat -an 查看端口的使用
IP地址:电脑在互联网的标识
socket(简称:套接字)
它是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:
它能实现不同带闹闹见的进程间通信,我们网络上各种各种各样的服务大多都是
基于Socket 来完成通信的:
from socket import socket,AF_INET,SOCK_STREAM # 创建了一个客户端的socket client = socket(AF_INET,SOCK_STREAM) conn_address = ('10.0.102.132',9001) # 告诉客户端要连接的服务器的地址和端口号 client.connect(conn_address) client.send('gang要来了!!!'.encode('utf-8')) client.close()
''' 创建一个socket服务器 ''' from socket import socket, AF_INET, SOCK_STREAM # 创建socket对象 server = socket(AF_INET, SOCK_STREAM) # 绑定端口号 server.bind(('', 9001)) # 开启监听状态 监听: server.listen(5) while True: socket, addr_info = server.accept() # 阻塞的 # print(socket, addr_info) data = socket.recv(512).decode('utf-8') print('{}发过来的消息式:{}'.format(addr_info[0],data)) socket.close() print(addr_info, '离开了')
另一种方式:
from socket import socket, AF_INET, SOCK_STREAM # 创建了一个客户端的socket client = socket(AF_INET, SOCK_STREAM) conn_address = ('10.0.102.144', 9001) # 告诉客户端要连接的服务器的地址和端口号 client.connect(conn_address) while True: msg = input('客户端输入:') client.send(msg.encode('utf-8')) if msg == '88': break # 接收信息 recv_msg = client.recv(512).decode('utf-8') print('服务器会话:', recv_msg) if recv_msg == '88': break client.close()
from socket import socket, AF_INET, SOCK_STREAM # 创建socket对象 server = socket(AF_INET, SOCK_STREAM) # 绑定端口号 server.bind(('', 9001)) # 开启监听状态 监听: server.listen(5) while True: socket, addr_info = server.accept() # 阻塞的 # print(socket, addr_info) while True: data = socket.recv(512).decode('utf-8') print('客户端说:{}'.format(data)) if data=='88': break msg = input('服务器输入:') socket.send(msg.encode('utf-8')) if msg =='88': break socket.close() print(addr_info, '离开了')
方式三:
from socket import socket, AF_INET, SOCK_STREAM # 创建了一个客户端的socket from threading import Thread client = socket(AF_INET, SOCK_STREAM) conn_address = ('10.0.102.144', 9002) # 告诉客户端要连接的服务器的地址和端口号 client.connect(conn_address) # 任务 def send_msg(sock): while True: msg = input('输入要发送的消息:') sock.send(msg.encode('utf-8')) def recv_msg(sock): while True: data = sock.recv(512).decode('utf-8') if len(data) == 0: break print('\n收到了服务器端的消息:', data) Thread(target=send_msg, args=(client,)).start() Thread(target=recv_msg, args=(client,)).start() # client.close()
from socket import socket, AF_INET, SOCK_STREAM from threading import Thread # 创建socket对象 server = socket(AF_INET, SOCK_STREAM) # 绑定端口号 server.bind(('', 9002)) # 开启监听状态 监听: server.listen(5) # 任务 def send_msg(sock): while True: msg = input('输入要发送的消息:') sock.send(msg.encode('utf-8')) def recv_msg(sock): while True: data = sock.recv(512).decode('utf-8') if len(data) == 0: break print('\n收到了客户端的消息:', data) while True: sock, addr_info = server.accept() # 阻塞的 t1 = Thread(target=send_msg, args=(sock,)) t2 = Thread(target=recv_msg, args=(sock,)) t1.start() t2.start() # sock.close() print(addr_info, '离开了')
浏览器服务端模式:
''' client:浏览器客户端 server端: 浏览器请求: server端响应 ''' from gevent import monkey,socket # 创建socket对象 monkey.patch_all() import gevent server = socket.socket() # 绑定端口号 server.bind(('', 9001)) # 开启监听状态 监听: server.listen(5) def handle_client(sock): print('--------------') recv_data = sock.recv(1024).decode('utf-8') print(recv_data) res_line = 'HTTP/1.1 200 OK\r\n' res_header = 'Content-Type:text/html;charset=utf-8\r\nServer:Apache\r\n' msg = '<h1>你回去吧!!!</h1>' response = res_line+res_header+'\r\n'+msg sock.send(response.encode('utf-8')) sock.close() while True: sock, addr_info = server.accept() # 阻塞的 print(addr_info,'来了') gevent.spawn(handle_client,sock)
# __author:gang # date: 2019/8/15 # coding = utf-8 import socket from multiprocessing import Process import re # 常量名字大写 HTML_ROOT_DIR = './html' class HttpServer(object): def __init__(self): # 创建TCP服务端 self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 服务端口可以重复启动,不会被占用 self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) def bind(self, port1): # 绑定端口 self.server.bind(('', port1)) def start(self): # 设置监听 self.server.listen(128) while True: client_socket, client_address = self.server.accept() client = Process(target=self.handle_client, args=(client_socket,)) client.start() # 在主进程中关闭连接 client_socket.close() def handle_client(self, client_socket): # 获取客户端请求的数据 request_data = client_socket.recv(1024) request_lines = request_data.splitlines() for line in request_lines: print(line) request_start_line = request_lines[0].decode('utf-8') # 使用正则表达式,得到请求的路径或者index.html file_path = re.match(r'\w+ +(/[^ ]*)', request_start_line) file_name = file_path.group(1) print('file_name:', file_name) if '/' == file_name: file_name = '/index.html' try: # 打开文件读取/html/index.html文件内容,以二进制方式 f = open(HTML_ROOT_DIR + file_name, 'rb') except: # 构造相应数据 response_start_line = "HTTP/1.1 404 Not Found File\r\n" response_headers = "Server:My Server\r\n" response_body = "sorry!file not found!" else: # 文件存在,正常处理 file_data = f.read() # 关闭文件 f.close() # 构造相应数据 response_start_line = "HTTP/1.1 200 OK\r\n" response_headers = "Server:My Server\r\n" response_body = file_data.decode("utf-8") # 拼接数据:注意响应头和响应体要加上\r\n response = response_start_line + response_headers + "\r\n" + response_body print("response data:", response) # client_socket.send(bytes(response,"utf-8")) client_socket.send(response.encode("utf-8")) client_socket.close() def main(): http_server = HttpServer() http_server.bind(7788) http_server.start() if __name__ == '__main__': main()
原文地址:https://www.cnblogs.com/rungang/p/11360554.html
- 区块链小白投资入门操作指南(上)
- 《我的WCF之旅》博文系列汇总
- 网站出现“Service Unavailable”提示该如何解决
- Silverlight 4 中摄像头的运用—part1
- Silverlight 4 中摄像头的运用—part1
- Silverlight 4 中数据绑定发生的变化
- 未来3年 人工智能如何影响法律行业?5位权威专家给出趋势
- silverlight.js详解.
- 前端三大框架vue,angular,react大杂烩
- Silverlight制作scrollbar.
- [Silverlight动画]转向行为 - 躲避行为
- WCF后续之旅(1): WCF是如何通过Binding进行通信的
- CaseStudy(showcase)布局篇-列表的排放与遮罩
- [Silverlight动画]转向行为 - 追捕行为
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 每日一题 | 约瑟夫问题
- 编码的浪漫:完美序列化的官方评测
- 【Vulnhub】symfonos2
- PWN入门(unsafe unlink)
- tf_cnn_benchmark 显存问题
- Spark on Kubernetes PodTemplate 的配置
- IO ports
- 【android系统】使用s3来上传下载文件
- 【Spark on Kubernetes】Executor环境变量
- Python获取字典值
- 应用程序InetlliJ IDEA不能打开
- yum install空间不足
- prometheus-nginxlog-exporter构建Nginx日志监控
- s3cmd put文件的过程
- Ceph RGW配置Nginx代理出现S3Error: 403 (Forbidden)