python核心编程

文章目录

  • 网络编程基础概念
    • 第一个网络通信
    • 协议概念
    • udp
    • tcp
      • 初识
      • tcp中的现象
      • tcp文件传输
      • 验证客户端的合法性
      • socketserver
  • 多线程
    • 进程
      • 1.概念
      • 2.多进程实现一个并发的socket的server
      • 3.开启进程的另一种方法
      • 4.process类的其他方法
      • 5.守护进程
      • 6.锁
      • 7.队列
        • 生产者消费者模型
      • 8.异步阻塞
        • 生产者消费者模型
    • 线程
      • 1.threading模块
      • 2.守护线程
      • 3.线程锁
      • 4.单例模式
      • 5.递归锁和死锁
      • 6.队列
      • 7.池
    • 协程
      • 1.协程概述
  • 数据库
    • 1.初识
    • 2.表操作
    • 3.索引
    • 4.pymysql模块
    • 5.事务、锁
  • web服务
    • 1.初识http
    • 2、web框架

网络编程基础概念

# 打基础
#   了解一些网络的基础知识
#   简单的了解一些底层的网络通信
# 网络的概念
# 基于原生的网络模块来实现通信


# 概念
# 不变的:mac地址 能够唯一表示你这台机器的
# 变化的:ip地址  能够更好地更方便的找到你的机器
# 局域网:网段    交换机  不能理解IP地址,只能理解mac地址
# 局域网和局域网之间通信了:
#   网管  路由器 可以理解IP地址

# IP地址
#   0.0.0.0-255.255.255.255
#
#   公网地址:需要我们申请购买的地址
#   内网地址:保留字段
#          192.168.0.0- 192.168.255.255  内网地址
#           172.16.0.0- 172.31.255.255  内网地址
#           10.0.0.0- 10.255.255.255  内网地址
#   特殊的ip地址:
#       127.0.0.1  本地回环地址  测试的时候用的
#   子网掩码也是一个ip地址,用来判断两台机器在不在一个局域网内
# ipv6 0:0:0:0:0:0-FFFFFF:FFFFFF:FFFFFF:FFFFFF:FFFFFF:FFFFFF:192.168.12.3


# ip/mac  确认机器的
# 端口 0-65535   确认机器上的具体应用

# 概念整理
#   局域网的概念
#       交换机
#           在同一个局域网内的机器有交换机负责通信
#           交换机只认识mac地址
#           可以完成广播 组播 单薄
#       单播 -- mac地址(在网卡上)
#   局域网之间通信
#       路由器
#           提供网关ip,同一个局域网的所有机器共享一个网关
#           我们不能访问除了本局域网之外的其他内网的ip地址
#       子网掩码
#           用来判断两台机器是不是在一个网段内
#   ip地址:ipv4协议, ipv6协议
#   mac地址:arp协议(通过ip找mac)
#   端口port:0-65535, 用来确认机器上的具体应用


# 网络开发结构
#   C/S架构
#       client客户端  我们用的 需要安装的
#       server服务端
#   B/S架构:百度,博客园
#       browser浏览器
#       server服务端
#   C/S架构和B/S架构什么关系?
#       B/S架构也是C/S架构中的一种
#   C/S架构的好处;
#       可以离线使用/功能更完善/安全性更高
#   B/S架构的好处:(发展的方向)
#       不用安装就可以使用
#       统一PC端用户的入口
#

第一个网络通信

  • 永远是服务端先启动,客户端才能启动

server端

import socket

sk = socket.socket()
sk.bind(('192.168.121.1', 9000))  # 绑定  ip + 端口
sk.listen()  # 监听

conn, adder = sk.accept()
conn.send(b'hello')  # 发送信息
msg = conn.recv(1024)  # 接收的最大字节
print(msg)
conn.close()

sk.close()

client端

import socket

sk = socket.socket()
sk.connect(('192.168.121.1', 9000))


msg = sk.recv(1024)
print(msg)
sk.send(b'byebye')

sk.close()

协议概念

# 5层协议
# 应用层   python
# 传输层   port       四层路由器  (四层交换机)
# 网络层   ipv4 ipv6  路由器  (三层交换机)
# 数据链路层   mac arp协议  网卡  (二层交换机)
# 物理层

# 7层协议
# 应用层 (表示层 会话层)
# 传输层   port
# 网络层   ipv4 ipv6  路由器
# 数据链路层   mac arp协议  交换机
# 物理层





# tcp 和 udp
# tcp 打电话 - 线下缓存高强视频/qq远程控制/发邮件
#   需要先建立链接,然后才能通信
#   占用连接/可靠(消息不会丢失)/实时性高/慢

#   建立链接 - 三次握手
#   断开链接 - 四次握手
#   什么是三次握手?什么是四次握手?为什么握手是三次/四次?这个过程都传递了哪些信号

# udp 发短信 - 在线播放视频
#   不需要建立链接,就可以通信
#   不占用连接/不可靠(消息因为网络不稳定丢失)/快

udp

  • server
import socket

sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1', 8666))

while True:
    msg, adder = sk.recvfrom(1024)  # 接收 , adder为对方地址 ip+port
    # if msg.decode('utf-8').lower() == 'q':
    #     print('会话结束')
    #     break
    if msg.decode('utf-8').lower() == 'q':
        continue
    print(msg.decode('utf-8'))
    send_msg = input('请输入:')
    sk.sendto(send_msg.encode('utf-8'), adder)
    # if send_msg.lower() == 'q':
    #     print('会话结束')
    #     break
  • client
import socket

sk = socket.socket(type=socket.SOCK_DGRAM)

server = ('127.0.0.1', 8666)
while True:
    send_msg = input('请输入:')
    sk.sendto(send_msg.encode('utf-8'), server)  # 发送
    if send_msg.lower() == 'q':
        print('会话结束')
        break
    msg = sk.recv(1024).decode('utf-8')  # 接收
    if msg.lower() == 'q':
        print('会话结束')
        break
    print(msg)

tcp

初识

  • server
import socket

sk = socket.socket()
sk.bind(('192.168.121.1', 9000))  # 申请操作系统的资源
sk.listen()  # 监听

# while True:  # 可以和多个客户端建立连接
#     conn, adder = sk.accept()  # conn里储存的是一个客户端和我server端连接信息
#     conn.send(b'hello')  # 发送信息
#     msg = conn.recv(1024)  # 接收的最大字节
#     print(msg)
#     conn.close()  # 挥手 断开连接

conn, adder = sk.accept()  # conn里储存的是一个客户端和我server端连接信息
while True:
    send_msg = input('请输入:')
    conn.send(send_msg.encode('utf-8'))  # 发送信息
    if send_msg.upper() == 'Q':
        break
    msg = conn.recv(1024).decode('utf-8')  # 接收的最大字节
    if msg.upper() == 'Q':
        break
    print(msg)
conn.close()  # 挥手 断开连接

sk.close()  # 归还申请的操作系统的资源
  • client
import socket

sk = socket.socket()
sk.connect(('192.168.121.1', 9000))

while True:
    msg2 = sk.recv(1024).decode("utf-8")
    if msg2.upper() == 'Q':
        break
    print(msg2)
    send_msg = input("请输入:")
    sk.send(send_msg.encode('utf-8'))
    if send_msg.upper() == 'Q':
        break

sk.close()

tcp中的现象

  • 不知道对方传输的字节大小
  • 使用struct模块,转换为4字节
    1. 转:struct.pack(‘i’, len(msg2))
    1. 现接收字节大小:le = sk.recv(4)
    1. 再转为原来字节:struct.unpack(‘i’, le)[0] (注意返回的是元组, 所以取第一个)
  • 每条信息都要转

  • server
import socket
import struct

sk = socket.socket()
sk.bind(('127.0.0.1', 8666))  # 地址绑定
sk.listen()  # 监听

conn, adder = sk.accept()  # 建立连接
msg1 = input(">>>").encode('utf-8')
msg2 = input('>>>').encode('utf-8')

# num1 = str(len(msg1))  # 不能超过 9999字节
# ret = num1.zfill(4)  # 转为4位 用 0 补字节

blen = struct.pack('i', len(msg1))  # 可以把两个g的内容转化为4个字节
conn.send(blen)  # 先发送传输的字节大小
conn.send(msg1)

blen = struct.pack('i', len(msg2))  # 可以把两个g的内容转化为4个字节
conn.send(blen)  # 先发送传输的字节大小
conn.send(msg2)

conn.close()
sk.close()

# 粘包现象  只出现在tcp协议中,因为tcp协议 多条信息之间没有边界,并且还有一大堆优化算法
#   发送端:两条消息很短且发送的间隔很短
#   接收端:接收消息不及时

# 导致粘包问题的本质:
  • client
import socket
import struct

sk = socket.socket()
sk.connect(('127.0.0.1', 8666))

le = sk.recv(4)  # 先接收传输的字节大小
le = struct.unpack('i', le)[0]  # 解字节 ,返回元组
msg1 = sk.recv(le).decode('utf-8')
print(msg1)

le = sk.recv(4)  # 先接收传输的字节大小
le = struct.unpack('i', le)[0]  # 解字节 ,返回元组
msg2 = sk.recv(le).decode('utf-8')
print(msg2)


sk.close()

struct模块

import struct

num = 1234568
num2 = 123
num3 = 8

ret = struct.pack('i', num)  # 可以把两个g的内容转化为4个字节
print(len(ret))
de = struct.unpack('i', ret)  # 解字节  返回元组
print(de)

ret = struct.pack('i', num2)  # 可以把两个g的内容转化为4个字节
print(len(ret))
de = struct.unpack('i', ret)  # 解字节  返回元组
print(de)

ret = struct.pack('i', num3)  # 可以把两个g的内容转化为4个字节
print(len(ret))
de = struct.unpack('i', ret)  # 解字节  返回元组
print(de)


-----------------------------
4
(1234568,)
4
(123,)
4
(8,)
-----------------------------

tcp文件传输

  • server
import json
import socket
import struct
# 解决粘包问题
sk = socket.socket()
sk.bind(('127.0.0.1', 9696))
sk.listen()

conn, _ = sk.accept()

msg_len = conn.recv(4)  # 接收四个字节
msg_len = struct.unpack('i', msg_len)[0]  # 解字节,返回的值是元组,取第一个,就是原来的数据大小

msg = conn.recv(msg_len)
msg = json.loads(msg)  # 加载msg

with open(msg['filename'], 'wb') as f:  # msg['filename'] 文件名字
    while msg['filesize'] > 0:  # msg['filesize'] 文件大小
        content = conn.recv(1024)
        # 传输的过程中,接收的不一定是1024个字节,因为要过转建站交换机
        msg['filesize'] -= len(content)  # 收多少减多少
        f.write(content)

conn.close()
sk.close()

  • client
import json
import socket
import os
import struct
# 发送
sk = socket.socket()
sk.connect(('127.0.0.1', 9696))

# 文件名
# 文件大小
abs_path = r'D:\PyCharmProject\python-核心编程\hehe'

filename = os.path.basename(abs_path)  # 拿到文件名
filesize = os.path.getsize(abs_path)  # 文件大小 xxx字节
dic = {'filename': filename, 'filesize': filesize}
str_dic = json.dumps(dic)  # 将dic转为字符串json
b_dic = str_dic.encode('utf-8')
mlen = struct.pack('i', len(b_dic))  # 转化为四字节
sk.send(mlen)  # 4个字节表示字典长度
sk.send(b_dic)  # 具体的字典数据


with open(abs_path, 'rb') as f:  # 打开文件
    while filesize > 0:
        content = f.read(1024)  # 一次发送文件的大小
        filesize -= 1024  # 文件的大小改变
        sk.send(content)  # 发送1024大小的文件

sk.close()

验证客户端的合法性

# # 随机生成一个字符串
# import os
# ret = os.urandom(16)
# print(ret)
#
# import hashlib
# sha = hashlib.sha1(秘钥)
# sha.update(随机字符串)
# result = sha.hexdigest()


# 第二种方法
import hashlib
import hmac  # 替代hashlib模块
import os

#                  秘钥+随机字符串
h = hmac.new(b'alex_sb', os.urandom(32), hashlib.sha256)
ret = h.digest()
print(ret)
  • server

    import hashlib
    import os
    import socket
    
    secret_key = b'alex_sb'
    sk = socket.socket()
    sk.bind(('127.0.0.1', 9696))
    sk.listen()
    
    conn, adder = sk.accept()
    # 创建一个随机的字符串
    rand = os.urandom(32)
    # 发送随机字符串
    conn.send(rand)
    # 根据发送的字符串+ secrete key 进行摘要
    sha = hashlib.sha1(secret_key)
    sha.update(rand)
    res = sha.hexdigest()
    # 等待接收客户端的摘要结果
    res_client = conn.recv(1024).decode('utf-8')
    # 做对比
    if res_client == res:
        print('是合法客户端')
        # 如果一致, 就显示合法客户端
        # 并继续操作
        conn.send(b'hello')
    else:
        conn.close()
    # 如果不一致立即关闭连接
    
  • client

import socket
import hashlib

secret_key = b'alex_sb'
sk = socket.socket()
sk.connect(('127.0.0.1', 9696))

# 接收客户端发送的随机字符串
rand = sk.recv(32)
# 根据发送的字符串 + secrete key 进行摘要
sha = hashlib.sha1(secret_key)
sha.update(rand)
res = sha.hexdigest()
# 根据结果发送会server端
sk.send(res.encode('utf-8'))
# 继续和server端进行通信
msg = sk.recv(1024).decode('utf-8')
print(msg)

socketserver

  • server
import time
import socketserver


class MyServer(socketserver.BaseRequestHandler):
    # 必须要重写handel方法, 内部类规定的
    def handle(self):  # 所有的客户端都经过这个程序(每个客户端都有自己的handel)
        conn = self.request  # requests 是和客户端的连接
        while True:
            try:
                content = conn.recv(1024).decode('utf-8')
                conn.send(content.upper().encode('utf-8'))
                time.sleep(0.5)
            except ConnectionError:
                break


server = socketserver.ThreadingTCPServer(('127.0.0.1', 9696), MyServer)
server.serve_forever()  # 不关闭
  • client
import socket

sk = socket.socket()
sk.connect(('127.0.0.1', 9696))
while True:
    sk.send('i love you'.encode('utf-8'))
    msg = sk.recv(1024).decode('utf-8')
    print(msg)

多线程

进程

1.概念

# 进程的三状态图
#   就绪  运行 阻塞

# 进程的调度算法
#   给所有的进程分配资源或者分配cpu使用权的一种方法
#   短作业优先
#   先来先服务
#   多级反馈算法
#       多个任务队列,优先级从高到低
#       新来的任务总是优先级最高
#       每一个新任务几乎会立即获得一个时间片时间
#       执行完一个时间片之后会下降到下一个队列中
#       总是优先级高的任务都执行完,才执行优先级低的任务
#       并且优先级越高时间片越高

# 进程的开启和关闭
# multiple 多元化的
# processing 进程
# multiprocessing 多远的处理进程的模块


# from multiprocessing import Process
# import os
#
#
# def func():
#     print(os.getpid(), os.getppid())
#     # pid process id  进程id
#     # ppid parent process id  父进程id
#
#
# if __name__ == '__main__':
#     # 只会在子主进程中执行所有的代码,你写在name=main下
#     print('main:', os.getpid(), os.getppid())
#     p = Process(target=func)
#     p.start()


# 为什么要用if __name__ == '__main__':
#   a = 1


# 能不能给子进程传递参数
# from multiprocessing import Process
# import os
#
#
# def func(name, age):
#     print(os.getpid(), os.getppid(), name, age)
#
#
# if __name__ == '__main__':
#     # 只会在子主进程中执行所有的代码,你写在name=main下
#     print('main:', os.getpid(), os.getppid())
#     p = Process(target=func, args=('李锦彪', 84))  # 传参
#     p.start()

# 能不能获取子进程的返回值
#   不能


# 能不能同时开启多个子进程
#   可以
# import time
# from multiprocessing import Process
# import os
#
#
# def func(name, age):
#     print('%s start' % name)
#     time.sleep(1)
#     print(os.getpid(), os.getppid(), name, age)
#
#
# if __name__ == '__main__':
#     # 只会在子主进程中执行所有的代码,你写在name=main下
#     print('main:', os.getpid(), os.getppid())
#     arg_lit = [('ljn', 54), ('jv', 12), ('hdhd', 11)]
#     for i in arg_lit:
#         p = Process(target=func, args=i)  # 传参
#         p.start()  # 异步非阻塞


# join的用法
# import time
# from multiprocessing import Process
#
# def func(name, age):
#     print('%s 的年龄: %d' % (name, age))
#     time.sleep(1)
#     print('发送完毕')
#
# if __name__ == '__main__':
#     arg_lit = [('李锦彪', 18), ('黄欣宇', 12), ('锦欣宇', 11)]
#     p_lst = []
#     for i in arg_lit:
#         p = Process(target=func, args=i)  # 传参
#         p.start()  # 异步非阻塞
#         p_lst.append(p)
#     for p in p_lst:
#         p.join()  # 阻塞:直到p这个进程执行完,才继续执行代码
#     print('所有的邮件发送完毕')


# 同步阻塞,异步非阻塞
#   同步阻塞:join
#   异步非阻塞:start

# 多进程之间的数据是否隔离   是
# from multiprocessing import Process
# n = 0
# def func():
#     global n
#     n += 1
#
# if __name__ == '__main__':
#     p_1 = []
#     for i in range(0, 100):
#         p = Process(target=func)
#         p.start()
#         p_1.append(p)
#     for p in p_1:
#         p.join()
#     print(n)


# 使用多进程实现一个并发的socket的server
#

2.多进程实现一个并发的socket的server

server:

import socket
from multiprocessing import Process


def talk(conn):
    while True:
        msg = conn.recv(1024).decode('utf-8')
        print(msg)
        ret = msg.upper().encode('utf-8')
        conn.send(ret)
    conn.close()


if __name__ == '__main__':
    sk = socket.socket()
    sk.bind(('127.0.0.1', 9999))
    sk.listen()

    while True:  # 来一个开一个子进程
        conn, adder = sk.accept()
        Process(target=talk, args=(conn, )).start()
    sk.close()

client:

import socket
import time

sk = socket.socket()
sk.connect(('127.0.0.1', 9999))

while True:
    sk.send(b'hello')
    msg = sk.recv(1024).decode('utf-8')
    print(msg)
    time.sleep(0.5)
sk.close()

3.开启进程的另一种方法

import os
import time
from multiprocessing import Process


class MyProcess(Process):

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
        super().__init__()

    def run(self):
        time.sleep(1)
        print(os.getpid(), os.getppid(), self.a, self.b, self.c)


if __name__ == '__main__':
    print('-->', os.getpid())
    for i in range(10):
        p = MyProcess(11, 2, 3)
        p.start()

4.process类的其他方法

import os
import time
from multiprocessing import Process


class MyProcess(Process):

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
        super().__init__()

    def run(self):
        time.sleep(1)
        print(os.getpid(), os.getppid(), self.a, self.b, self.c)


if __name__ == '__main__':
    print('-->', os.getpid())
    p = MyProcess(11, 2, 3)
    p.start()
    print(p.pid, p.ident)
    print(p.name)
    print(p.is_alive())  # 查看进程是否还活着
    p.terminate()  # 强制结束一个子进程  同步 异步非阻塞
    print(p.is_alive())
    time.sleep(0.01)
    print(p.is_alive())

5.守护进程

import time
from multiprocessing import Process

def son1():
    while True:
        print('-->is son1')
        time.sleep(1)


def son2():
    for i in range(10):
        print('in son2')
        time.sleep(1)


if __name__ == '__main__':
    p1 = Process(target=son1)
    p1.daemon = True  # 表示设置p1 是一个守护进程
    p1.start()
    p2 = Process(target=son2)
    p2.start()
    time.sleep(3)  # 守护进程只进行3秒,3秒后回收资源
    print('in main 守护进程结束')
    # p2.join()  # 等待p2结束,守护进程结束


# 主进程会等待所有的子进程结束,是为了回收子进程的资源
# 守护进程会等待主进程的代码执行结束之后再结束, 而不是等待整个主进程结束
# 主进程的代码什么时候结束

6.锁

# 进程之间安全的问题
import time
from multiprocessing import Process, Lock
import json


def search(i):
    with open('ticket', encoding='utf-8') as f:
        ticket = json.load(f)
    print('%s :当前的余票是%s张' % (i, ticket['count']))


def buy_ticket(i):
    with open('ticket', encoding='utf-8') as f:
        ticket = json.load(f)
    if ticket['count'] > 0:
        ticket['count'] -= 1
        print('%s 买到票了' % i)
    time.sleep(0.1)
    with open('ticket', mode='w', encoding='utf-8') as f:
        json.dump(ticket, f)


def get_lock(i, lock):  # 加锁
    with lock:  # 代替acquire和release 并且在此基础上做一些异常处理, 保证即便一个进程的代买出错退出了,也会归还钥匙
        search(i)
        buy_ticket(i)


if __name__ == '__main__':
    lock = Lock()
    for i in range(10):
        Process(target=get_lock, args=(i, lock)).start()


# import time
# from multiprocessing import Lock, Process
#
#
# def func(n, lock):
#     lock.acquire()  # 拿钥匙
#     print('%s 被锁起来的码' % n)
#     time.sleep(1)
#     lock.release()  # 换钥匙
#
#
# if __name__ == '__main__':
#     lock = Lock()
#     for i in range(10):
#         Process(target=func, args=(i, lock)).start()

7.队列

生产者消费者模型

# 进程之间的数据隔离
# 进程之间的通信(IPC)Inter Process communication
#   基于文件:同一台机器上的多个进程之间通信
#       基于socket的文件级别的通信来完成数据传递的
#   基于网络:同一台机器或者多台机器上的多进程通信
#       第三方工具(消息中间件)
#           memcache
#           redis
#           rabbitmq
# #           kafka
# from multiprocessing import Queue, Process
#
#
# def pro(q):
#     for i in range(10):
#         print(q.get())
#
#
# def son(q):
#     for i in range(10):
#         q.put('hello %s' % i)
#
#
# if __name__ == '__main__':
#     q = Queue()
#     p = Process(target=son, args=(q, ))
#     p.start()
#     p = Process(target=pro, args=(q,))
#     p.start()


# 生产者消费者模型
#   爬虫的时候
#   分布式操作:celery
#   本质:就是让生产数据和消费数据的效率达到平衡并且最大话的效率
import random
import time
from multiprocessing import Process,Queue


def consumer(q, name):  # 消费者:通常取得数据后还要进行某些操作
    while True:
        food = q.get()
        if food:
            print('%s 吃了 %s' % (name, q.get()))
        else: break


def producer(q, name, food):  # 生产者:通常在放数据之前需要先通过某些代码来获取数据
    for i in range(10):
        foodi = '%s%s' % (food, i)
        print('%s 生产了 %s' % (name, foodi))
        time.sleep(random.random())
        q.put(foodi)


if __name__ == '__main__':
    q = Queue()
    p = Process(target=consumer, args=(q, '李锦彪'))
    p1 = Process(target=producer, args=(q, '黄欣宇', '黄金'))
    p2 = Process(target=producer, args=(q, '锦欣宇', '西瓜'))
    p.start()
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    q.put(None)

8.异步阻塞

生产者消费者模型

线程

1.threading模块

# import time
# from threading import Thread
#
#
# def func(i):
#     print('start %s' % i)
#     time.sleep(1)
#     print('end%s' % i)
#
#
# if __name__ == '__main__':
#     p_1 = []
#     for i in range(10):
#         t = Thread(target=func, args=(i,))
#         t.start()
#         p_1.append(t)
#     for i in p_1:
#         i.join()
#     print('所有的线程都执行完了')
#
#
# # 线程不能从外部关闭terminate
# # 所有的子线程只能是自己执行完代码之后就关闭
# # current_thread() 获取当前所在线程的对象,current_thread().ident 获取线程的id
# # enumerate 列表, 储存了所有活着的线程的对象,包括主线程
# # active_count 数字,储存了所有活着的线程个数


#
# 面向对象的方式起线程
# from threading import Thread
#
#
# class MyThread(Thread):
#     def __init__(self, a, b):
#         self.a = a
#         self.b = b
#         super().__init__()
#
#     def run(self):
#         print(self.ident)
#
#
# t = MyThread(1, 2)
# t.start()  # 开启线程中执行run()方法
# print(t.ident)


# 线程之间的数据
from threading import Thread
n = 100


def func():
    global n
    n -= 1


t_1 = []
for i in range(100):
    t = Thread(target=func)
    t.start()
    t_1.append(t)
for i in t_1:
    i.join()
print(n)

2.守护线程

import time
from threading import Thread


def son():
    while True:
        print('in son')
        time.sleep(1)


def sons():
    for i in range(10):
        print('in sons****')
        time.sleep(1)


if __name__ == '__main__':
    t = Thread(target=son)
    t.daemon = True  # 守护线程
    t.start()

    Thread(target=sons).start()

# 主线程会等待子线程结束之后才结束
# 为什么?
#   主线程结束进程就会结束
# 守护线程随着主线程的结束而结束
# 守护线程会在主线程的代码结束之后继续守护其他子线程
#   守护进程会随着主进程的代码结束而结束,如果主进程代码结束之后还有其他子进程在运行,守护进程不守护
#   守护线程 随着主线程的结束而结束,如果主线程代码结束之后还有其他子线程在运行,守护线程也守护

3.线程锁

import time
from threading import Thread, Lock
n = 0


def add(lock):
    with lock:
        for i in range(5520000):
            global n
            n += 1


def sub(lock):
    with lock:
        for i in range(5520000):
            global n
            n -= 1


if __name__ == '__main__':
    t_1 = []
    lock = Lock()
    for i in range(2):
        t1 = Thread(target=add, args=(lock,))
        t1.start()
        t2 = Thread(target=sub, args=(lock,))
        t2.start()
        t_1.append(t1)
        t_1.append(t2)
    for i in t_1:
        i.join()
    print(n)

4.单例模式

import time
from threading import Thread


class A:
    from threading import Lock
    __instance = None
    lock = Lock()

    def __new__(cls, *args, **kwargs):
        with cls.lock:
            if not cls.__instance:
                time.sleep(0.00001)  # cpu 轮转
                cls.__instance = super().__new__(cls)
            return cls.__instance


def func():
    a = A()
    print(a)


if __name__ == '__main__':
    for i in range(10):
        Thread(target=func).start()

# 不要操作全局变量, 不要在类里操作静态变量
# queue logging 数据安全的

5.递归锁和死锁

import time
from multiprocessing import Process, RLock, Lock
from threading import Thread

# Lock 互斥锁   效率高  多把锁容易出现死锁现象
# RLock递归(recursion)锁  效率相对低  解决死锁现象好

# l = Lock()
# l.acquire()
# print('haha')  # 希望被锁住的内容
# l.release()

# r = RLock()  # 在同一个线程中可以被acquire()多次
# r.acquire()
# print('希望被锁住的内容')
# r.release()


# def func(i, lock):
#     lock.acquire()
#     print(i, ':start')
#     lock.release()
#
#
# if __name__ == '__main__':
#     lock = Lock()
#     for i in range(5):
#         p = Thread(target=func, args=(i, lock)).start()


# ******************死锁现象****************
noodle_lock = Lock()
fork_lock = RLock()


def eat(name):
    fork_lock.acquire()
    print(name, '抢到面了')
    print(name, '抢到叉子了')
    print(name, '吃面')
    time.sleep(1)
    fork_lock.release()
    print(name, '放下叉子了')
    print(name, '放下面了')


def eat2(name):
    fork_lock.acquire()
    print(name, '抢到叉子了')
    print(name, '抢到面了')
    print(name, '吃面')
    fork_lock.release()
    print(name, '放下面了')
    print(name, '放下叉子了')


if __name__ == '__main__':
    Thread(target=eat, args=('李锦彪',)).start()
    Thread(target=eat2, args=('黄欣宇',)).start()
    Thread(target=eat, args=('锦欣宇',)).start()
    Thread(target=eat2, args=('二蛋',)).start()

6.队列

import queue  # 线程之间的数据安全的容器队列

q = queue.Queue(4)  # fifo 先进先出的队列
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get())

try:
    q.get_nowait()
except Exception as e:
    print(e)

print('队列为空继续其他内容')
print('*' * 50)

from queue import LifoQueue  # last in first out 后进先出

lq = LifoQueue()
lq.put(1)
lq.put(2)
lq.put(3)
print(lq.get())
print(lq.get())
print(lq.get())
print('*' * 50)

from queue import PriorityQueue  # 优先级队列

priq = PriorityQueue()

priq.put((1, 'a'))
priq.put((5, 'b'))
priq.put((6, 'x'))
priq.put((4, 'y'))
print(priq.get())
print(priq.get())
print(priq.get())
print(priq.get())

7.池

# 什么是池
#   要在程序开始的时候,还没提交任务先创建几个线程或者进程
#   放在一个池子里,这就是池
# 为什么要用池
#   如果先开好进程/线程,那么有任务之后就可以直接使用池中的数据了
#   并且开好后的线程或者进程会一直存在池中,可以被多个任务反复利用
#       这样极大地减少了开启/关闭/调度线程/进程 的时间开销
#   池中的线程/进程个数控制了操作系统需要调度的任务个数,控制池中的单位
#       有利于提高操作系统的效率,减轻操作系统的负担
import random
import time
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
from threading import current_thread


def func(name, n):
    print(name, current_thread().ident, n)
    time.sleep(random.randint(1, 3))


tp = ThreadPoolExecutor(20)
for i in range(20):
    tp.submit(func, '李锦彪', 2)

# 向池中传数据,一次加入即可

协程

1.协程概述

# 协程
#   是操作系统不可见的
#   协程本质就是一条协程,多个任务在一条线程上来回切换,来规避io操作,就达到我们将一条线程中的io操作降到最低的目的
# gevent = 利用 greenlet  底层模块完成的切换 + 自动规避io的功能
# asynico = 利用  yield(让步)   底层语法完成的切换 + 自动规避io的功能
#   tornado 异步的web框架
#   yield from  更好的实现协程
#   send 更好的实现协程

# 进程 数据隔离 数据不安全  操作系统级别     开销非常大   能利用多核
# 线程 数据共享 数据不安全  操作系统级别     开销小      不能利用多核
#   一些和文件操作相关的io只有系统能感知到
# 协程 数据共享 数据安全    用户级别        更小        不能利用多核
#   协程的所有的切换都基于用户,只有在用户级别能够感知到的io操作才会用协程模块做切换来规避(socket, 请求网页)

# 用户级别的协程还有什么好处:
#   减轻了操作系统的负担
#   一条线程下如果开了多个协程,那么给操作系统的印象是线程很忙,这样能争取一些时间片时间来被cpu执行,程序的效率就提高了

数据库

1.初识

# Innodb存储引擎  mysql5.6之后的默认存储引擎
#   支持事务:为了保证数据的完整性,将多个操作变成原子性操作 :  保持数据安全
#   支持行级锁:修改的行少的时候 :  修改数据频繁的操作
#   表级锁:批量修改多行时 :   对于大量数据得到同时修改
#   支持外键:约束两张表中的关联字段不能随意的添加/删除 :  能够降低数据增删改的出错率


# 写入数据
#   insert into 表 values(1,2,3,4,5)
#   insert into 表 (1,2,3)value(1,2,3)


# 数据类型
#   float(5, 2)  保留2位小数,并四舍五入(一共多少位, 小数后多少位)


# 数据类型-时间
#             写入标准   表示
#   date    :20220312  YYYY-MM-DD 年月日
#   time    :121953    HH:MM:SS   时分秒
#   datetime:20220312213512  YYYY-MM-DD HH:MM:SS 年月日时分秒


# 数据类型-字符串
#   char(18)    最多只能表示255个字符
#       定长存储   存取速度快
#       ‘alex’   ‘alex             ’
#       身份证号、手机号码、QQ号、username、password、银行卡号
#   varchar(18)    最多表示65535个字符
#       变长存储, 节省空间,存取速度慢
#       ‘alex’   ‘alex4’
#       评论、朋友圈、微博


# set和enum
#   enum:单选行为
#   set :多选行为


# 表的完整性约束
#   无符号的:unsigned
#   不能为空:not null
#   默认 值:default xx
#   不能重复:unique
#   主键(非空+唯一):primary key  (一张表只有一个)
#       联合主键:primary key(字段1,字段2.。。)
#   自增:auto_increment
#   外键:foreign_key(本表的外键键) references (其他的表)
#   cascade方式:在父表上update/delete记录时,同步update/delete掉子表的匹配记录
#       on update cascade


# 表与表之间的关系
# 一对多
#   电脑   软件
#   订单   商品
# 多对一
#   学生   班级
#   学院   学校
# 多对多  (第三张表 两个外键)
#   学生  班级  多对一
#       多个学生是一个班级
# 一对一
#   客户  学生
#   unique foreign key

2.表操作

# 增  insert into 表(字段。。。) values (值。。。) 或 insert into 表 values (值。。。)
# 删
#   delete from 表 where 条件;
#   truncate table 表;  完全删除表
# 改  update 表 set 字段=xx, 字段=xx where 条件


# 查***********************************************
# 简单查询
#   select 字段 from 表;
#   字段重命名为name:select 字段 ‘name’ from 表;
#   避免重复:select distinct 字段 from 表;
#   避免重复:select distinct 字段,字段 from 表;

#   concat('a', 'v', 'b')  拼接:avb :select concat(id, ':', name) from 表;
#       默认自动拼接:avb :select concat_ws('':, id, name, on) from 表;    id:name:on

# where 筛选所有符合条件的行**************************
#   比较运算符  <>!=
#   范围
#       between  1 and  2000
#       in
#   模糊匹配
#       like
#           % 通配符n个字符
#           _ 通配符1个字符
#       regexp
#   逻辑运算
#       and not or
#       判断是否为空:
#           select * from 表 where name is not null;  不为空
#           select * from 表 where name is null;      为空

# 分组 ********************************************
#   根据谁分组,可以求最大小值,数量,平均值,总和,但是这个求出来的值只是和分组字段对应
#   并不和其他任何字段对应,这个时候查出来的其他字段都不生效
#   group by 分组:select * from 表 group by 分组条件;
# 聚合函数:count max min sum avg
#   select count(字段) from 表 group by 分组条件;
# having 过滤语句
#   在having条件中可以使用条件函数
#   select 字段,count(salary) from 表 group by 分组条件 having count(salary) > 1000;
# order by  排序  默认从小到大; order by desc 从大到小排
#   select * from 表 order by 字段;
#   select * from 表 order by 字段,字段;  字段一相同时按字段二排
# limit m,n = limit n offset m
#   从m+1项开始,取 n 项
#   如果不写m,默认为0
#       select * from 表 limit m,n;


# 多表查询****************************************
# 连表查询(快,比子查询好)
#   select * from 表1,表2 where 条件;  列:(表1.字段=表2.字段)
#   表与表之间的连接方式
#       内连接:select * from 表1 inner join 表2 on 条件;
#       外连接:
#           左外连接:优先显示左边的表内容
#               select * from 表1 left join 表2 on 条件;
#           右外连接:优先显示右边的表内容
#               select * from 表1 right join 表2 on 条件;
#           全外连接: full join
#               select * from 表1 left join 表2 on 条件 union select * from 表1 right join 表2 on 条件;
# 子查询
#   select * from 表 where 条件 in (select 条件 from 表);

3.索引

4.pymysql模块

必须的步骤

conn = pymysql.connect(host='',user='',password='',database='');  # 连接数据库
cur = conn.cursor()  # 游标,为了执行mysql语句准备

ret = cur.execute('sql....')  # 执行SQL语句,有返回值加参数ret

cur.execute('sql....')  # 没有返回值,修改表内容
cur.commit()  # 需要提交执行
print(cur.rowcount)  # 获取操作影响的行数

cur.close()
conn.close()
import pymysql

conn = pymysql.connect(host='127.0.0.1', user='root', password='187365', database='ljb')
# cursor=pymysql.cursors.DictCursor拿到的值放在字典中
cur = conn.cursor(cursor=pymysql.cursors.DictCursor)  # cursor游标, cur 准备操作

# 通常执行异常操作
# cur.execute('select * from gds_goods;')  # 执行mysql语句
# print(cur.rowcount)  # 获取操作影响的行数

# try:
#     cur.execute('insert into gds_goods (gds_memo, gds_name, gds_no, gds_price) '
#                 'values ("大傻子","二傻子","22222","88888");')
#     conn.commit()  # 修改表数据,需要提交
# except:
#     conn.rollback()  # 回滚:第一条语句出错时,回滚执行第二条

# ret = cur.fetchone()  # 拿某一个值
# print(ret)
#
# ret = cur.fetchmany(2)  # 拿多个值
# print(ret)

# ret = cur.fetchall()  # 拿所有的值
# for i in ret:
#     print(i)

# username = input('请输入账号:')
# password = input('请输入密码:')
#
# sql = 'select * from personal_information where username=%s and password=%s;'
# cur.execute(sql, (username, password))  # sql语句 + 参数(元组或列表)
#
# print(cur.fetchone())
#
# cur.close()
# conn.close()

5.事务、锁

# 锁
#   防止同时执行
#       begin;  开始任务
#         执行sql语句
#       commit;  提交任务

web服务

1.初识http

服务器

import socket

sk = socket.socket()
sk.bind(('127.0.0.1', 9696))
sk.listen()

while 1:
    conn, adder = sk.accept()
    mvg = conn.recv(1024).decode('utf-8')
    print(mvg)
    conn.send(b'HTTP/1.1 200 ok\r\n\r\n')  # http请求信息
    with open('my.html', 'rb') as f:  # 读取html
        data = f.read()
    conn.send(data)  # 发送html

html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<h1>你好!世界h1>
body>
html>

get方法

  • a标签、form表单

post方法

  • 一般用来提交数据

2、web框架

import socket
from threading import Thread
import time

sk = socket.socket()
sk.bind(('127.0.0.1', 9696))
sk.listen()


def html(conn):
    time_target = str(time.time())
    with open('my-2.html', 'r', encoding='utf-8') as f:  # 读取html,以字符串形式读取,以便后续操作(动态)
        data = f.read()  # 读取字符串
    data = data.replace('$xxoo$', time_target)  # 替换
    data = data.encode('utf-8')
    conn.send(data)  # 发送html
    conn.close()


def css(conn):
    with open('test.css', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()


def js(conn):
    with open('javascript.js', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()


def jpg(conn):
    with open('1.jpg', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()


def ico(conn):
    with open('1.ico', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()


def jqurey(conn):
    with open('jquery-3.6.0.js', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()


urlpatterns = [  # 反射准备
    ('/', html),
    ('/test.css', css),
    ('/1.jpg', jpg),
    ('/1.ico', ico),
    ('/javascript.js', js),
    ('/jquery-3.6.0.js', jqurey)
]

while 1:
    conn, adder = sk.accept()  # 等待接收信息
    request_mvg = conn.recv(1024).decode('utf-8')  # 接收信息

    path = request_mvg.split('\r\n')[0].split(' ')[1]  # 网页需要请求的路径

    conn.send(b'HTTP/1.1 200 ok\r\n\r\n')  # http请求信息:协议/版本  状态码  状态码原因短语

    for i in urlpatterns:
        if path == i[0]:
            print(path)
            Thread(target=i[1], args=(conn,)).start()  # 线程处理并发

ket
from threading import Thread
import time

sk = socket.socket()
sk.bind((‘127.0.0.1’, 9696))
sk.listen()

def html(conn):
time_target = str(time.time())
with open(‘my-2.html’, ‘r’, encoding=‘utf-8’) as f: # 读取html,以字符串形式读取,以便后续操作(动态)
data = f.read() # 读取字符串
data = data.replace(‘ x x o o xxoo xxoo’, time_target) # 替换
data = data.encode(‘utf-8’)
conn.send(data) # 发送html
conn.close()

def css(conn):
with open(‘test.css’, ‘rb’) as f:
data = f.read()
conn.send(data)
conn.close()

def js(conn):
with open(‘javascript.js’, ‘rb’) as f:
data = f.read()
conn.send(data)
conn.close()

def jpg(conn):
with open(‘1.jpg’, ‘rb’) as f:
data = f.read()
conn.send(data)
conn.close()

def ico(conn):
with open(‘1.ico’, ‘rb’) as f:
data = f.read()
conn.send(data)
conn.close()

def jqurey(conn):
with open(‘jquery-3.6.0.js’, ‘rb’) as f:
data = f.read()
conn.send(data)
conn.close()

urlpatterns = [ # 反射准备
(‘/’, html),
(‘/test.css’, css),
(‘/1.jpg’, jpg),
(‘/1.ico’, ico),
(‘/javascript.js’, js),
(‘/jquery-3.6.0.js’, jqurey)
]

while 1:
conn, adder = sk.accept() # 等待接收信息
request_mvg = conn.recv(1024).decode(‘utf-8’) # 接收信息

path = request_mvg.split('\r\n')[0].split(' ')[1]  # 网页需要请求的路径

conn.send(b'HTTP/1.1 200 ok\r\n\r\n')  # http请求信息:协议/版本  状态码  状态码原因短语

for i in urlpatterns:
    if path == i[0]:
        print(path)
        Thread(target=i[1], args=(conn,)).start()  # 线程处理并发

你可能感兴趣的:(python之路,python)