pdb调试
python -m pdb xxx.py
l---->显示当前的代码list
n---->向下执行一行代码next
c---->continue 继续执行代码
b---->break 添加断点
clear--->删除断点
p---->打印一个变量的值
a---->打印所有的形参数据
s---->进入到一个函数
q---->quit退出调试
r---->return快速执行到函数的最后一行
多任务理解
为了同时为多个客户端服务,需要能够同时处理多个网络连接的方法,python包括三个主要的方法:forking、threading和异步I/O(也被称之为不闭塞的socket)
进程 vs 程序
编写完毕的diamante,没有运行的时候称之为程序
正在运行着的代码,就成为进程。进程,除了包含代码以外,还有需要运行的环境等,和程序有区别
forking
调度算法 时间片轮转 优先级调度 并发 并行
fork函数
fork:原意为刀叉,计算机体系进程中有个讲述进程的例子,在餐桌上,很多科学家吃饭,但刀叉有限,有些人必须等到别人放下刀叉才能使用刀叉吃饭,比喻进程有限,程序需要等到有空闲进程才能继续运行。
Windows下没有fork函数,默认是单用户的,和Linux不一样
每个进程都有个唯一的ID,称为进程ID,PID,可以用ps获取进程的信息。
死锁:当服务器和客户端都停下来等待一个行为出现的时候,有可能会出现死锁,小心使用协议并适当使用超时来避免死锁。
创建⼦进程时, 只需要传⼊⼀个执⾏函数和函数的参数, 创建⼀个Process实例, ⽤start()⽅法启动, 这样创建进程⽐fork()还要简单。
join()⽅法可以等待⼦进程结束后再继续往下运⾏, 通常⽤于进程间的同步。
语法结构
Process([group [, target [, name [, args [, kwargs]]]]])
target: 表示这个进程实例所调⽤对象;
args: 表示调⽤对象的位置参数元组;
kwargs: 表示调⽤对象的关键字参数字典;
name: 为当前进程实例的别名;
group: ⼤多数情况下⽤不到;
Process类常⽤⽅法:
is_alive(): 判断进程实例是否还在执⾏;
join([timeout]): 是否等待进程实例执⾏结束, 或等待多少秒;等待对象标记的进程结束之后才会继续往下走。
start(): 启动进程实例(创建⼦进程) ;
run(): 如果没有给定target参数, 对这个对象调⽤start()⽅法时, 就将执
⾏对象中的run()⽅法;
terminate(): 不管任务是否完成, ⽴即终⽌;
#coding=utf-8
from multiprocessing import Process
import time
def test():
for i in range(5):
print("---test---")
time.sleep(1)
p = Process(target=test)
p.start()
p.join()#堵塞,等着
print("---main---")
进程池
需要创建的⼦进程数量不多时, 可以直接利⽤multiprocessing中的Process动态成⽣多个进程, 但如果是上百甚⾄上千个⽬标, ⼿动的去创建进程的⼯
作量巨⼤, 此时就可以⽤到multiprocessing模块提供的Pool⽅法。
初始化Pool时, 可以指定⼀个最⼤进程数, 当有新的请求提交到Pool中时,如果池还没有满, 那么就会创建⼀个新的进程⽤来执⾏该请求; 但如果池中
的进程数已经达到指定的最⼤值, 那么该请求就会等待, 直到池中有进程结束, 才会创建新的进程来执⾏
from multiprocessing import Pool
import os
import random
import time
def worker(num):
for i in range(5):
print("===pid=%d==num=%d="%(os.getpid(),num))
time.sleep(1)
pool = Pool(3)
for i in range(0,10):
print("---%d---"%i)
pool.apply_async(worker,(i,))
print("---start---")
pool.close()
pool.join()
print("---end---")
压力测试
极短的时间里通过模拟大量真实用户的使用情况来看是否能顶住压力。
三种多进程方式的比较
队列queue
process之间有时需要通信,可以使用multiprocessing模块的Queue实现多进程之间的数据传递
#coding=utf-8
from multiprocessing import Queue
q=Queue(3) #初始化⼀个Queue对象, 最多可接收三条put消息
q.put("消息1")
q.put("消息2")
print(q.full()) #False
q.put("消息3")
print(q.full()) #True
#因为消息列队已满下⾯的try都会抛出异常, 第⼀个try会等待2秒后再抛出异常, 第⼆个Try会⽴
try:
q.put("消息4",True,2)
except:
print("消息列队已满, 现有消息数量:%s"%q.qsize())
try:
q.put_nowait("消息4")
except:
print("消息列队已满, 现有消息数量:%s"%q.qsize())
#推荐的⽅式, 先判断消息列队是否已满, 再写⼊
if not q.full():
q.put_nowait("消息4")
#读取消息时, 先判断消息列队是否为空, 再读取
if not q.empty():
for i in range(q.qsize()):
print(q.get_nowait())
运行结果
False
True
消息列队已满, 现有消息数量:3
消息列队已满, 现有消息数量:3
消息1
消息2
消息3
Queue.qsize(): 返回当前队列包含的消息数量;
Queue.empty(): 如果队列为空, 返回True, 反之False ;
Queue.full(): 如果队列满了, 返回True,反之False;
Queue.get([block[, timeout]]): 获取队列中的⼀条消息, 然后将其从列队中移除, block默认值为True;
Queue.get_nowait(): 相当Queue.get(False);
进程池中的Queue
如果要使⽤Pool创建进程, 就需要使⽤multiprocessing.Manager()中的Queue(), ⽽不是multiprocessing.Queue()