【第七节】python多线程及网络编程
目录
一、python多线程
1.1 多线程的作用
1.2 python中的 threading 模块
1.3 线程锁
二、python网络编程
2.1 通过socket访问网络
2.2 python2.x中的编码问题
2.3 python3的编码问题
一、python多线程
1.1 多线程的作用
多线程技术在计算机编程中扮演着重要的角色,它主要有以下几个作用:
1. **提高程序的响应性**:在单线程程序中,如果某个操作需要较长时间,比如读取大文件或进行复杂计算,整个程序会在这段时间内无法响应用户的其他操作。而多线程允许程序在执行耗时操作的同时,其他线程可以继续响应用户输入,从而提高程序的响应速度和用户体验。
2. **提高资源利用率**:现代计算机通常有多个处理器或核心。多线程允许程序同时运行在多个处理器上,从而更充分地利用系统资源,提高处理速度和效率。
3. **简化程序结构**:通过将复杂的任务分解为多个并行的线程,可以使程序的逻辑更加清晰和模块化。每个线程负责一部分任务,便于管理和维护。
4. **实现并发操作**:在某些应用场景中,需要同时进行多个独立的任务,如服务器处理多个客户端请求、图形界面同时响应用户输入和后台数据处理等。多线程使得这些并发操作成为可能。
5. **提高执行效率**:对于可以并行执行的任务,多线程可以显著减少总的执行时间。例如,在数据处理、图像渲染、科学计算等领域,多线程可以大幅提升处理速度。
然而,多线程编程也带来了一些挑战,如线程同步问题、死锁风险、资源竞争等,需要开发者仔细设计和实现,以确保程序的正确性和稳定性。
1.2 python中的 threading 模块
Python中用于多线程编程的内置模块是 `threading`。下面我将详细解释如何使用 `threading` 模块来启动多线程。
### 使用 `threading` 模块启动多线程
1. **导入 `threading` 模块**:
import threading
2. **定义线程函数**:
这个函数将作为新线程的入口点。
def my_thread_function(arg1, arg2):# 线程执行的代码print(f"Thread is running with arguments: {arg1}, {arg2}")
3. **创建 `Thread` 对象**:
在创建 `Thread` 对象时,可以传入线程函数和参数。
thread = threading.Thread(target=my_thread_function, args=("hello", "world"))
4. **启动线程**:
调用 `start()` 方法启动线程。
thread.start()
5. **等待线程完成(可选)**:
如果需要等待线程执行完毕,可以调用 `join()` 方法。
thread.join()
### 完整示例
以下是一个完整的示例,展示了如何使用 `threading` 模块创建和启动多个线程:
import threadingdef my_thread_function(arg1, arg2):print(f"Thread {threading.current_thread().name} is running with arguments: {arg1}, {arg2}")# 创建多个线程
threads = []
for i in range(5):thread = threading.Thread(target=my_thread_function, args=(f"hello_{i}", f"world_{i}"))threads.append(thread)thread.start()# 等待所有线程完成
for thread in threads:thread.join()print("All threads have finished.")
在这个示例中,我们创建了5个线程,每个线程执行 `my_thread_function` 函数,并传递不同的参数。最后,我们使用 `join()` 方法确保主线程等待所有子线程完成后再继续执行。
通过这种方式,您可以利用 `threading` 模块在Python中实现多线程编程,从而提高程序的并发性和响应性。
1.3 线程锁
在多线程编程中,所有线程共享代码和数据资源。这种共享性带来了一个主要风险:多个线程可能同时访问和修改同一个变量,导致不可预期的结果。为了解决这一问题,大多数编程语言提供了锁机制来确保线程安全。
### 问题代码示例
import threadingg_Num = 0def threadProc():global g_Numfor i in range(1000000):g_Num = g_Num + 1 # 修改数据thread1 = threading.Thread(name="hello1", target=threadProc)
thread2 = threading.Thread(name="hello2", target=threadProc)
thread1.start()
thread2.start()
thread1.join()
thread2.join()print(g_Num)
在这个示例中,两个线程同时对 `g_Num` 进行递增操作,导致最终打印出来的数字不可预期。
### 使用锁机制解决问题
为了确保线程安全,可以使用锁来保护对 `g_Num` 的访问。以下是修正后的代码:
import threadinglock = threading.Lock()
g_Num = 0def threadProc():global g_Numfor i in range(1000000):lock.acquire() # 获取锁g_Num = g_Num + 1 # 修改数据lock.release() # 释放锁thread1 = threading.Thread(name="hello1", target=threadProc)
thread2 = threading.Thread(name="hello2", target=threadProc)
thread1.start()
thread2.start()
thread1.join()
thread2.join()print(g_Num)
通过使用锁,我们确保在任何时刻只有一个线程能够进入锁定范围并修改 `g_Num`,从而避免了竞态条件,确保最终结果的可预期性。
二、python网络编程
2.1 通过socket访问网络
Python 提供了两种不同层次的网络服务接口:
1. **低级网络服务**:这一层支持基本的 Socket 功能,它实现了标准的 BSD Sockets API,允许开发者访问底层操作系统 Socket 接口的所有方法,从而进行更底层的网络操作。
2. **高级网络服务**:这一层包含模块 SocketServer,它提供了一系列服务器中心类,旨在简化网络服务器的开发过程,使得开发者能够更快速地构建网络应用。
**什么是 Socket?**
Socket,又称为“套接字”,是应用程序用于网络通信的一种抽象。通过 Socket,应用程序可以发送请求或响应网络请求,实现不同主机间或同一台计算机上不同进程间的通信。Socket 是网络编程的基础,它封装了复杂的网络通信细节,使得开发者能够更容易地编写网络应用程序。
socket()函数
Python 中,我们用 socket()函数来创建套接字,语法格式如下:
socket.socket([family[, type[, proto]]])
参数
- family: 套接字家族可以使 AF_UNIX 或者 AF_INET。
- type: 套接字类型可以根据是面向连接的还是非连接分为
SOCK_STREAM
或SOCK_DGRAM
。 - protocol: 一般不填默认为 0。
Socket 对象(内建)方法
简单示例如下:
服务端代码:
# 导入 socket 模块
import socketdef main():print("~~~~~服务端启动~~~~~")# 1. 创建 socketsSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 2. 绑定sSock.bind(('192.168.1.125', 1234)) # IP地址 可用本地IP测试: 127.0.0.1# 3. 监听sSock.listen(5)# 4. 处理连接cSock, addr = sSock.accept()print("客户端连接成功")cSock.send(str('欢迎:').encode('utf-8'))# 5、6 发送、接收数据while True:print(cSock.recv(1024).decode('utf-8'))inStr = input('>>>: ')if inStr == 'quit':breakcSock.send(str(inStr).encode('utf-8'))# 7. 关闭套接字cSock.close()sSock.close()if __name__ == "__main__":main()
客户端代码:
# 导入 socket 模块
import socketdef main():print("~~~~~客户端启动~~~~~")# 1. 创建 socketcSock = socket.socket()# 2. 连接服务器host = '192.168.1.125' # IP地址 可用本地IP测试: 127.0.0.1port = 1234 # 设置端口号cSock.connect((host, port))# 3、4 发送、接收数据while True:print(cSock.recv(1024).decode('utf-8'))inStr = input('>: ')if inStr == 'quit':breakcSock.send(str(inStr).encode('utf-8'))# 5. 关闭套接字cSock.close()if __name__ == "__main__":main()
2.2 python2.x中的编码问题
在Python 2.x版本中,存在两个主要的字符串类:`unicode` 和 `str`,它们都继承自 `basestring`。
`str` 类是带编码的,默认情况下使用 ASCII 编码。因此,如果你的程序中包含中文字符串,默认情况下会报错。可以通过设置Python 2中的字符默认编码来解决这个问题。
# coding:utf-8 # 默认使用UTF-8编码# coding:gbk # 默认使用GBK编码
`unicode` 类是不带编码的,用于表示已知文明中的任何一个字符。需要注意的是,`unicode` 并不是一种编码方式。
示例:
ul = u"中国" # 字符串 unicode类型print ul # 输出: u'\u4e2d\u56fd'print len(ul) # 输出: 2u2 = u'hello'print u2 # 输出: u'hello'print len(u2) # 输出: 5sl = "中国" # str 类型,字节串print sl # 输出: '\xd6\xd0\xb9\xfa'(中文 GBK 编码,控制台不指定中文默认 GBK)print len(sl) # 输出: 4s2 = "hello"print s2 # 输出: 'hello'print len(s2) # 输出: 5
在Python 2中,可以在字符串和字节串之间进行转换:
- `encode`:将字符串按指定方式进行编码,转换成字节流(`str`),存放在内存中。
- `decode`:将字节流按指定方式进行解码,转换成字符串(`unicode`),用于显示。
可以使用 `chardet` 模块来判断字节流的编码:
import chardet
raw = u'12AB好'
print chardet.detect(raw.encode('utf-8')) # 输出: {'encoding': 'utf-8', 'confidence': 0.99}
print chardet.detect(raw.encode('gbk')) # 输出: {'encoding': 'GB2312', 'confidence': 0.99}
在C++中,多字节集通常是GBK编码,而宽字节集是UTF-16编码。字符使用哪种方式进行编码,就应该使用哪种方式进行解码。以下是几种常见情况:
1. C++端发送过来的是GBK编码,我们需要显示,那么应该使用 `decode("GBK")` 转换成 `unicode` 便于显示。
2. C++端发送过来的是UTF-16编码,我们需要显示,那么应该使用 `decode("UTF-16")` 转换成 `unicode` 便于显示。
3. C++端发送过来的数据需要Python端转发到其他C++端,不需要转换。
4. Python端要直接给C++端发送字符串,那么应该根据C++端使用多字节集还是宽字节集,使用 `encode("GBK")` 或者 `encode("UTF-16")` 之后再发送给C++端。
5. 如果你直接使用字节串,那么应该先使用 `decode("UTF-8")` 转换成 `unicode`,再使用 `encode("GBK")` 或者 `encode("UTF-16")` 再发送给C++端。
示例代码:
c++端代码:
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>#pragma comment(lib, "ws2_32.lib")// 数据包 1024 + 4 + 4 = 1032
struct NETMSGINFO {int MSGTYPE; // 消息类型int nMsgLen; // 消息大小char szMsgBuff[1024]; // 消息内容
};int main() {// 1. 初始化环境WSADATA wsd = {};if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {std::cerr << "WSAStartup failed!" << std::endl;return 1;}// 2. 创建套接字SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (sock == INVALID_SOCKET) {std::cerr << "socket creation failed!" << std::endl;WSACleanup();return 1;}// 3. 连接sockaddr_in addr = {};addr.sin_family = AF_INET;addr.sin_port = htons(0x1234);addr.sin_addr.s_addr = inet_addr("127.0.0.1");if (connect(sock, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {std::cerr << "connect failed!" << std::endl;closesocket(sock);WSACleanup();return 1;}// 4. 发送数据NETMSGINFO netbuf = {};netbuf.MSGTYPE = 1; // 可以用宏代替,上线strcpy_s(netbuf.szMsgBuff, 1024, "xxx:上线了");netbuf.nMsgLen = strlen(netbuf.szMsgBuff); // 字符长度,注意Python中字符不以0结尾if (send(sock, (char*)&netbuf, sizeof(netbuf), 0) == SOCKET_ERROR) {std::cerr << "send failed!" << std::endl;closesocket(sock);WSACleanup();return 1;}// 5. 接收数据if (recv(sock, (char*)&netbuf, sizeof(netbuf), 0) == SOCKET_ERROR) {std::cerr << "recv failed!" << std::endl;closesocket(sock);WSACleanup();return 1;}std::cout << netbuf.szMsgBuff << std::endl;// 6. 清理环境closesocket(sock);WSACleanup();return 0;
}
python端代码:
import socket
import structdef main():# 创建TCP套接字sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 绑定端口sock.bind(("127.0.0.1", 0x1234))# 监听sock.listen(socket.SOMAXCONN)# 等待连接clientsock, addr = sock.accept()print(f"Connection from {addr}")# 获取消息大小是发送数据结构大小Msg = clientsock.recv(1032)# 进行格式拆包,由于字符长度不确定,暂时不解包消息msgtype, nMsgLen = struct.unpack('ii', Msg[0:8])# 第二次根据长度解包,指定解包字符长度,使用切片方式msgbuff, = struct.unpack(f'{nMsgLen}s', Msg[8:8+nMsgLen])# 字符需要进行解码,因为VS中默认是以GBK编码方式print(msgbuff.decode('gbk'))# 回复客户端消息,构建一个数据包# 这个数据需要进行GBK编码,否则VS中解析不了字符sendbug = '你好\n'.encode('gbk')# 打包数据msg = struct.pack('ii1024s', 0, len(sendbug), sendbug)# 发送数据clientsock.send(msg)# 关闭套接字clientsock.close()sock.close()if __name__ == "__main__":main()
2.3 python3的编码问题
在Python 3中,默认使用UTF-8编码,并且明确区分了文本字符和二进制数据,分别用`str`和`bytes`类型表示。
s1 = "abc" # str类型,字符串
s2 = b"abc" # bytes类型,二进制字节流
s1 = "中国" # str类型,字符串
s2 = b"中国" # bytes类型,不支持非ASCII字符,这样会报错
在Python 2中,`str`类型在Python 3中对应`bytes`类型,表现为字节,转换是通过`encode`方法,用于存储。
在Python 2中,`Unicode`类型在Python 3中对应`str`类型,表现为字符,转换是通过`decode`方法,用于显示。
`encode`和`decode`方法用于在`str`和`bytes`之间进行转换。
示例:
s = "18CM好棒"
print(s.encode()) # 默认使用UTF-8编码
# 输出: b'18CM\xe5\xa5\xbd\xe6\xa3\x92'
print(s.encode("gbk")) # 使用GBK编码
# 输出: b'18CM\xba\xc3\xb0\xb2'print(b'18CM\xe5\xa5\xbd\xe6\xa3\x92'.decode()) # 默认使用UTF-8解码
# 输出: '18CM好棒'
print(b'18CM\xba\xc3\xb0\xb2'.decode("gbk")) # 使用GBK解码
# 输出: '18CM好棒'
需要注意的是,`encode`和`decode`方法的默认参数都是UTF-8。
相关文章:

【第七节】python多线程及网络编程
目录 一、python多线程 1.1 多线程的作用 1.2 python中的 threading 模块 1.3 线程锁 二、python网络编程 2.1 通过socket访问网络 2.2 python2.x中的编码问题 2.3 python3的编码问题 一、python多线程 1.1 多线程的作用 多线程技术在计算机编程中扮演着重要的角色&a…...

Linux Shell编程--变量
前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除 变量: bash作为程序设计语言和其它高级语言一样也提供使用和定义变量的功能 预定义变量、环境变量、自定义变量、位置变量 一、自定义变…...

软文写作必须掌握的技巧有哪些?
现代互联网飞速发展的时代,硬广逐渐变的效果越来越差,而软文推广已经成为网络营销的重要组成部分了,一篇好的软文往往能为你的产品、网站带来意想不到的效果。 用于做营销的软文,我们不能像写普通文章那样随意。一篇优质的软文会让…...

探索灵办AI:智能办公的好帮手
引言 随着AI工具的增多,选择合适的AI助手变得尤为重要。ChatGPT的订阅费用高且功能单一,很多小伙伴开始寻找更具性价比和多功能的替代品。灵办AI以其便捷、高效、多功能的特点,成为许多朋友的新宠。 灵办AI助手是一款多功能的全能AI助手&am…...

gin-vue-admin框架遇到AxiosError:Network Error怎么解决?
flipped-aurora/gin-vue-admin: 🚀ViteVue3Gin的开发基础平台,支持TS和JS混用。它集成了JWT鉴权、权限管理、动态路由、显隐可控组件、分页封装、多点登录拦截、资源权限、上传下载、代码生成器【可AI辅助】、表单生成器和可配置的导入导出等开发必备功能…...

作业zzz
【考查点】 考查SpringBoot相关的知识点,包括:依赖注入(DI)、面向切面编程(AOP),以及常用的SpringBoot组件。 【作业要求】 利用spring-boot-starter-web来搭建一个web服务。完成简单的用户管…...

python 空list如何表示
创建空列表: L List() 或者: L [] 这时L就是一个空列表。 需要注意的是,空列表不是None,因此 L [] If L is not None:# 这里的代码总是会被执行 检查列表是否为空要使用len(): L [] if len(L):# 这里的代码不会执…...

C++ const、constexpr与consteval作用与区别
C const、constexpr与consteval作用与区别 在C 常量表达式和编译时优化中,我们已经提到了常量、编译时常量与运行时常量的概念。为了加深理解,我们再重新明晰一下这三者的概念。 常量:初始化之后便不可修改的量。在c中使用const修饰的“变量”…...
solidity 数学和密码学函数
数学和密码学函数为开发者提供了一系列强大的工具,用于执行各种数学运算和加密操作 addmod(uint x, uint y, uint k) returns (uint) 计算 (x y) % k,加法会在任意精度下执行,并且加法的结果即使超过 2**256 也不会被截取。 从 0.5.0 版本…...

opencv-图像透视变换
透射变换是视角变化的结果,是指利用透视中心,像点,目标点共线的条件,按透视旋转定律使承影面(透视面)绕迹线(透视轴旋转某一角度,破坏原有的投影光束,仍能保持承影面上投影几何图形不变的变化) 它的本质将图…...
C++ 域
C 域 :: C中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找一个变量/函数/类型出处(声明或定义)的逻辑,所以有了域隔离,名字冲突就解决了。局部域和全局域除了…...

安装Supervisor队列进程、管理 Laravel 队列进程
在 CentOS 上安装 Supervisor 并配置 Laravel 的步骤如下: 1.安装 Supervisor: 使用以下命令安装 Supervisor: sudo yum install epel-release sudo yum install supervisor 2.配置 Supervisor: 创建一个新的 Supervisor 配置文…...

Windows入侵排查秘籍:锁死安全漏洞
文章目录 Windows入侵排查秘籍:锁死安全漏洞1 检查系统账号安全1.1 查看服务器是否有弱口令,远程管理端口是否对公网开放1.2 查看服务器是否存在可疑账号、新增账号1.3 结合日志,查看管理员登录时间、用户名是否存在异常 2 检查异常端口、进程…...
根据《广东省政务服务数字化条例》规定,政务服务数字化,是指将___广泛应用于政务服务,推动政务服务更加智能、便捷、高效的活动。()
根据《广东省政务服务数字化条例》规定,政务服务数字化,是指将___广泛应用于政务服务,推动政务服务更加智能、便捷、高效的活动。()查看试题完整内容答案 A、大数据B、人工智能 C、数字技术D、科学技术 根据《广州市支…...

git的基本操作和原理
基本操作 原理 Git是分布式版本控制系统,可以保存每次修改后的代码,方便我们随时返回。 根据用户所写的代码,自动生成commit号,这个版本号只与代码内容有关,只要代码内容不同,commit id 就不同。 使用哈希…...

Unity补完计划 之 SpriteRender
本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正 1.SpriteRenderer是什么 渲染精灵用的,是渲染的核心组件,有许多重要参数所以要详细讲一讲 Spri…...

数据结构第九讲:二叉树
数据结构第九讲:二叉树 1.实现链式结构二叉树1.1二叉树的节点结构1.2创建二叉树节点1.3前中后序遍历1.3.1前序遍历1.3.2中序遍历1.3.3后序遍历1.3.4总结 1.4二叉树结点的个数1.4.1错误示范1.4.2实现方法 1.5二叉树叶子结点的个数1.6二叉树第k层结点的个数1.7二叉树的…...

英伟达推出B200A瞄准OEM客群,预估2025年高端GPU出货量年增55%
市场近日传出NVIDIA(英伟达)取消B100并转为B200A,据TrendForce集邦咨询了解,NVIDIA仍计划在2024年下半年推出B100及B200,供应CSPs(云端服务业者)客户,并另外规划降规版B200A给其他企…...
Codeforces Round 962 (Div. 3)-补题
A. Legs 二分答案,最后取左端点的值,保险起见,还是再验算一次 bool check(int x){int an/4;if(a*4(x-a)*2>n) return true;return false; }void solve(){cin>>n;int l0,rn;while(l1<r){int midlr>>1;if(check(mid)) rmid…...
pandas的文本与序列化
文章目录 1.pandas的文本与序列化 result_data pd.DataFrame(json_data_list)with open(jsonl_file_path, w, encodingutf-8) as jsonl_file:result_data.to_json(orientrecords, linesTrue, force_asciiFalse, path_or_bufjsonl_file)数据不换行 df.at[i, column_name_transc…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...

力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)
cd /home 进入home盘 安装虚拟环境: 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境: virtualenv myenv 3、激活虚拟环境(激活环境可以在当前环境下安装包) source myenv/bin/activate 此时,终端…...