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协议

返回顶部

  • 说明:面向连接的、数据可靠、三次握手、四次挥手、数据校验、传输稍慢

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协议

返回顶部

  • 说明:面向无连接,数据不可靠,传输速度稍快,适合于对数据要求不太严格的情况

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

欢迎关注,敬请点赞!
返回顶部

原创文章 43 获赞 14 访问量 2867

猜你喜欢

转载自blog.csdn.net/weixin_45221012/article/details/103834357
今日推荐