欢迎关注,敬请点赞!
python基础——线程使用与网络编程
线程使用
线程简介
- 线程可以认为是轻量级的进程
- 一个进程中本身就包含一个线程(主线程)
- 线程是CPU分配时间(任务调度)的基本单位,调度是操作系统的事。
- 进程之间数据是独立的,线程之间数据是共享的
- 一个进程实现多任务,只要创建多个线程就可以了
- 进程的开销较大,而线程的开销较小
- GIL:Global Interpreter Lock的简写
- 他本身是CPython解释器的特性,只是因为大多数情况下CPython都是默认的解释器
- 因此很多人误认为GIL是python本身的特性
- python的多线程效率受到很大影响,几乎等于单线程的效率
- 线程模块
_thread
:低级模块,使用不够方便和灵活,极少用到threading
:高级模块,是对_thread
模块的封装,推荐使用
基础类_thread
-
示例:
import _thread import time def loop(num): print('子线程开始') print('参数:', num) print('子线程结束') if __name__ == '__main__': print('主线程开始') # 创建并启动一个子线程 _thread.start_new_thread(loop, (100,)) time.sleep(2) print('主线程结束')
封装类threading
基本使用
import threading
import time
def run(file):
print(file, '正在下载')
ct = threading.current_thread()
print('子线程中当前线程:', ct.name)
for i in range(1, 6):
time.sleep(1)
print('已下载{}%...'.format(i*20))
print(file, '下载完成')
if __name__ == '__main__':
print('主线程开始')
# 获取主线程
mt = threading.main_thread()
print('主线程:', mt.name)
# 获取当前线程
ct = threading.current_thread()
print('当前线程:', ct.name)
# 创建子线程
thr = threading.Thread(target=run, args=('美女.png',), name='图片下载')
# 查看当前进程中的活跃线程数量
print('活跃线程数量:', threading.active_count())
print('子进程激活状态:', thr.is_alive())
# 启动线程
thr.start()
print('活跃线程数量:', threading.active_count())
print('子进程激活状态:', thr.is_alive())
# 查看线程信息
print('线程信息:', threading.enumerate())
# 等待子线程结束
thr.join()
print('主线程结束')
数据共享:
返回顶部
全局变量可以共享
import threading
# 全局变量可以在线程之间共享
num = 100
def run():
global num
num += 10
print('子线程中修改全局变量num')
if __name__ == '__main__':
thr = threading.Thread(target=run)
thr.start()
thr.join()
print('主线程结束', num)
线程锁
import threading
num = 100
def run(n):
global num
for i in range(100000):
'''
# 获取锁
lock.acquire()
try:
num += n
num -= n
except Exception as e:
print('出现异常', e)
finally:
# 释放锁
lock.release()
'''
# 简化方案
with lock:
num += n
num -= n
if __name__ == '__main__':
# 线程锁
lock = threading.Lock()
thr1 = threading.Thread(target=run, args=(5,))
thr2 = threading.Thread(target=run, args=(10,))
thr1.start()
thr2.start()
thr1.join()
thr2.join()
print(num)
线程类
from threading import Thread
from time import sleep
class EmailThread(Thread):
def __init__(self, email):
super().__init__()
self.email = email
def run(self):
print('发送邮件开始')
print('发送邮件:', self.email)
for i in range(1, 6):
sleep(1)
print('发送进度:{}%'.format(i*20))
print('发送邮件完成')
if __name__ == '__main__':
print('主线程开始')
et = EmailThread('1024,节日快乐!')
et.start()
et.join()
print('主线程结束')
定时线程:延时线程
import threading
import os
def run():
os.system('calc')
if __name__ == '__main__':
# 创建定时任务
t = threading.Timer(3, run)
t.start()
t.join()
信号传递:线程控制
返回顶部
可以理解为一个线程控制另一线程的执行
import threading
from time import sleep
def run(num):
for i in range(num):
# 等待条件成立,条件不成立会阻塞
e.wait()
print('子线程执行:', i)
# 清除条件,为下次做准备
e.clear()
if __name__ == '__main__':
# 创建对象
e = threading.Event()
n = 3
thr = threading.Thread(target=run, args=(n,))
thr.start()
for i in range(n):
sleep(1)
print('主线程执行:', i)
# 设置条件,wait处将不再阻塞
e.set()
网络相关概念
-
OSI七层模型:Open System Interconnection,参考模型是国际标准化组织(ISO)制定的一个用于计算机或通信系统间互联的标准体系,一般称为OSI参考模型或七层模型。
-
TCP/IP:在OSI七层模型基础上简化出来的一套网络协议簇(四层模型),得到了广泛使用
-
TCP协议:传输控制协议
- 是有连接的,数据传输安全可靠
- 三次握手、四次挥手,数据检查,传输速度稍慢
- 窗口不再每次都检查,隔几次检查一次,源于现在准确度大大提高
-
UDP协议:用户数据报(User datagram)协议
- 无连接的,数据不可靠
- 传输速度稍快
-
IP地址:计算机的唯一标识
windows
系统查看:ipconfig
-
ping
:检查网络连通性- 示例:
ping 域名/IP
- 示例:
-
端口号:每个应用对应一个端口号
- 范围:0~65535
- 公认端口:0~1023
协议 端口 http 80 https 443 smtp 25 ftp 21 ssh 22 mysql 3306 redis 6379 - 其他端口:1024~65535
-
网络编程核心:
- 身份:
IP+PORT
- 类库:
socket
- 身份:
TCP协议
- 说明:面向连接的、数据可靠、三次握手、四次挥手、数据校验、传输稍慢
示例1:模拟http协议,向百度服务器发送请求
import socket
# family:选择协议族,socket.AF_INET表示IPv4
# type:传输层协议,socket.SOCK_STREAM表示TCP
skt = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
# 与服务器建立连接
skt.connect(('www.baidu.com', 80))
# 向服务器发送数据
skt.send(b'GET / HTTP/1.1\r\nHost:www.baidu.com\r\nConnection:close\r\n\r\n')
# 接收数据
data = []
while True:
temp = skt.recv(1024)
if temp:
data.append(temp)
else:
break
# 关闭套接字
skt.close()
# 拼接接收的内容
content = b''.join(data).decode('utf-8')
# print(content)
header, body = content.split('\r\n\r\n', 1)
# print(header)
print(body)
示例2:echo
服务器,接收到什么就返回什么
# 服务器端代码
import socket
import multiprocessing
def echo(skt, addr):
while True:
recv_data = skt.recv(1024)
print(f"{addr},{recv_data.decode('utf-8')}")
skt.send(recv_data)
if recv_data == b'byebye':
break
skt.close()
if __name__ == '__main__':
skt = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
skt.bind(('10.8.158.17', 8888))
skt.listen(100)
while True:
client_skt, client_addr = skt.accept()
p = multiprocessing.Process(target=echo, args=(client_skt, client_addr))
p.start()
client_skt.close()
# 客户端代码
import socket
skt = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
skt.connect(('10.8.158.17', 8888))
while True:
data = input('>>>: ')
skt.send(data.encode('utf-8'))
recv_data = skt.recv(1024)
print(f"服务器:{recv_data.decode('utf-8')}")
if recv_data == b'byebye':
break
skt.close()
UDP协议
- 说明:面向无连接,数据不可靠,传输速度稍快,适合于对数据要求不太严格的情况
示例1:udp协议模拟发送飞秋数据
import socket
# 创建套接字
skt = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# 准备数据 '版本号:数据报序号:用户名:主机名:命令:消息内容[:附加数据]'
data = '1:12345:Jerry:windows:32:大家好!'
# 发送数据
skt.sendto(data.encode('utf-8'), ('10.8.158.255', 2425))
示例2:udp协议实现echo服务器
# 服务器代码
import socket
skt = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
skt.bind(('10.8.158.17', 8888))
while True:
data, addr = skt.recvfrom(1024)
print(f"客户端{addr}:{data.decode('utf-8')}")
skt.sendto(data, addr)
# 客户端代码
import socket
skt = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
while True:
data = input('>>>: ')
skt.sendto(data.encode('utf-8'), ('10.8.158.17', 8888))
data, addr = skt.recvfrom(1024)
print(f"服务器:{data.decode('utf-8')}")
if data == b'byebye':
break
欢迎关注,敬请点赞!
返回顶部