requests 超时设置

超时(timeout) 为防止服务器不能及时响应,大部分发至外部服务器的请求都应该带着 timeout 参数。在默认情况下,除非显式指定了 timeout 值,requests 是不会自动进行超时处理的。如果没有 timeout,你的代码可能会挂起若干分钟甚至更长时间。 连接超时指的是在你的客户端实现到远端机器端口的连接时(对应的是connect()_),Request 会等待的秒数。一个很好的实践方法是把连接超时设为比 3 的倍数略大的一个数值,因为 TCP 数据包重传窗口 (TCP packet retransmission window) 的默认大小是 3。 一旦你的客户端连接到了服务器并且发送了 HTTP 请求,读取超时指的就是客户端等待服务器发送请求的时间。(特定地,它指的是客户端要等待服务器发送字节之间的时间。在 99.9% 的情况下这指的是服务器发送第一个字节之前的时间)。 如果你制订了一个单一的值作为 timeout,如下所示: r = requests.get(‘https://github.com’, timeout=5) 这一 timeout 值将会用作 connect 和 read 二者的 timeout。如果要分别制定,就传入一个元组: r

Read More requests 超时设置

Python微服务框架NameKo 性能体验

Nameko是Python下的一个微服务框架,小巧简洁,通过RabbitMq消息组件来实现RPC服务 Github:NameKo 一、准备工作 1.RabbitMq 使用docker安装 docker 管理页面为 localhost:15672,默认用户名密码 guest、 guest。 2.Nameko安装,直接使用pip3 install nameko安装即可 二、测试代码 1、服务端 service 使用@rpc 装饰器定义RPC服务 2、配置文件 config.yml 运行服务 nameko run –config config.yml service1 3、客户端 使用 4、上面使用cProfile测试性能 1次调用RPC开销在76毫秒 5、封装成http 6、使用wrt测试,mac使用brew install wrt 安装即可 1个线程,持续20秒100个连接 响应时间和直接RPC请求差不多 QPS并发量1344/sec,只能说一般般吧

python 彻底解读多线程与多进程

在此之前请完整阅读完 Python threading 多线程模块 Python multiprocess 多进程模块 GIL 全局解释器锁GIL(全局解释器锁,GIL 只有cpython有):在同一个时刻,只能有一个线程在一个cpu上执行字节码,没法像c和Java一样将多个线程映射到多个CPU上执行,但是GIL会根据执行的字节码行数(为了让各个线程能够平均利用CPU时间,python会计算当前已执行的微代码数量,达到一定阈值后就强制释放GIL)和时间片以及遇到IO操作的时候主动释放锁,让其他字节码执行。 作用:限制多线程同时执行,保证同一个时刻只有一个线程执行。 原因:线程并非独立,在一个进程中多个线程共享变量的,多个线程执行会导致数据被污染造成数据混乱,这就是线程的不安全性,为此引入了互斥锁。 互斥锁:即确保某段关键代码的数据只能又一个线程从头到尾完整执行,保证了这段代码数据的安全性,但是这样就会导致死锁。 死锁:多个子线程在等待对方解除占用状态,但是都不先解锁,互相等待,这就是死锁。 基于GIL的存在,在遇到大量的IO操作(文件读写,网络等待)代码时,使用多线程效率更高。 多线程一个CPU再同一个时刻只能执行一个线程,但是当遇到IO操作或者运行一定的代码量的时候就会释放全局解释器锁,执行另外一个线程。 就好像你要烧水和拖地,这是两个任务,如果是单线程来处理这两个任务的话,先烧水,等水烧开,再拖地。这样等待水烧开的时间就白白浪费了,倘若事交给多线程来做的话,就先烧水,烧水的过程中(相当于IO操作的时候)把时间资源让出来给拖地,拖完地后水也烧好了,这个就是多线程的优势,再同一个时间段做更多的事情,也就是再以后会降到的高并发。 它提供如下一些方法: t1 = threading.Thread(target=你写的函数名,args=(传入变量(如果只有一个变量就必须在后加上逗号),),name=随便取一个线程名):把一个线程实例化给t1,这个线程负责执行target=你写的函数名t1.start():负责执行启动这个线程t1.join():必须要等待你的子线程执行完成后再执行主线程t1.setDeamon(True):当你的主线程执行完毕后,不管子线程有没有执行完成都退出主程序,注意不能和t1.join()一起使用。threading.current_thread().name:打印出线程名12345这些方法一开始看可能会觉得有些多,不过不打紧,可以先把后面的代码看完在回过头看这些提供的方法就觉得很简单了。 单线程版本import time def mop_floor():print(‘我要拖地了’)time.sleep(1)print(‘地拖完了’) def heat_up_watrt():print(‘我要烧水了’)time.sleep(6)print(‘水烧开了’) start_time = time.time()heat_up_watrt()mop_floor()end_time = time.time()print(‘总共耗时:{}’.format(end_time-start_time))1234567891011121314151617返回结果: 我要烧水了水烧开了我要拖地了地拖完了总共耗时:7.00076627731323212345单线程一共耗时7秒 多线程版本import threadingimport time def mop_floor():print(‘我要拖地了’)time.sleep(1)print(‘地拖完了’) def heat_up_watrt():print(‘我要烧水了’)time.sleep(6)print(‘水烧开了’)

Read More python 彻底解读多线程与多进程

Python multiprocess 多进程模块

来自http://www.langzi.fun/Python%20multiprocess%20%E5%A4%9A%E8%BF%9B%E7%A8%8B%E6%A8%A1%E5%9D%97.html 需要注意的是,如果使用多进程,调用方法一定要加上 (Python中的multiprocess提供了Process类,实现进程相关的功能。但是它基于fork机制,因此不被windows平台支持。想要在windows中运行,必须使用该的方式),但是我有另一种方法在使用线程池的时候可以不使用name_mian,最下面说。 并且多线程就是开启多个线程,每个线程之间是不会互相通信互相干扰的,适用于密集计算。 案例一 基础用法 多进程的使用方法和多线程使用方法基本一样,所以如果你会多线程用法多进程也就懂了,有一点要注意,定义多进程,然后传递参数的时候,如果是有一个参数就是用args=(i,)一定要加上逗号,如果有两个或者以上的参数就不用这样。 运行结果: 案例二 数据通信 ipc:就是进程间的通信模式,常用的一半是socke,rpc,pipe和消息队列等。 multiprocessing提供了threading包中没有的IPC(比如Pipe和Queue),效率上更高。应优先考虑Pipe和Queue,避免使用Lock/Event/Semaphore/Condition等同步方式 (因为它们占据的不是用户进程的资源)。 使用Array共享数据 对于Array数组类,括号内的“i”表示它内部的元素全部是int类型,而不是指字符“i”,数组内的元素可以预先指定,也可以只指定数组的长度。Array类在实例化的时候必须指定数组的数据类型和数组的大小,类似temp = Array(‘i’, 5)。对于数据类型有下面的对应关系: 代码实例: 运行结果: 使用Manager共享数据 通过Manager类也可以实现进程间数据的共享,主要用于线程池之间通信,Manager()返回的manager对象提供一个服务进程,使得其他进程可以通过代理的方式操作Python对象。manager对象支持 list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value ,Array等多种格式。 代码实例: 使用queues的Queue类共享数据 multiprocessing是一个包,它内部有一个queues模块,提供了一个Queue队列类,可以实现进程间的数据共享,如下例所示: 运行结果: 例如来跑多进程对一批IP列表进行运算,运算后的结果都存到Queue队列里面,这个就必须使用multiprocessing提供的Queue来实现

Read More Python multiprocess 多进程模块

理解Python中的yield

通常的for…in…循环中,in后面是一个数组,这个数组就是一个可迭代对象,类似的还有链表,字符串,文件。它可以是list1 = [1, 2, 3],也可以是list1 = [x*x for x in range(3)]。 它的缺陷是所有数据都在内存中,如果有海量数据的话将会非常耗内存。 生成器是可以迭代的,但只可以读取它一次。因为用的时候才生成。比如 mygenerator = (x*x for x in range(3)),注意这里用到了(),它就不是数组,而上面的例子是[]。 理解的生成器(generator)能够迭代的关键是它有一个next()方法,工作原理就是通过重复调用next()方法,直到捕获一个异常。可以用上面的mygenerator测试。 带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代,工作原理同上。 yield 是一个类似 return 的关键字,迭代一次遇到yield时就返回yield后面的值。重点是:下一次迭代时,从上一次迭代遇到的yield后面的代码开始执行。 简要理解:yield就是 return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后开始。 带有yield的函数不仅仅只用于for循环中,而且可用于某个函数的参数,只要这个函数的参数允许迭代参数。比如array.extend函数,它的原型是array.extend(iterable)。 send(msg)与next()的区别在于send可以传递参数给yield表达式,这时传递的参数会作为yield表达式的值,而yield的参数是返回给调用者的值。——换句话说,就是send可以强行修改上一个yield表达式值。比如函数中有一个yield赋值,a = yield 5,第一次迭代到这里会返回5,a还没有赋值。第二次迭代时,使用.send(10),那么,就是强行修改yield 5表达式的值为10,本来是5的,那么a=10 send(msg)与next()都有返回值,它们的返回值是当前迭代遇到yield时,yield后面表达式的值,其实就是当前迭代中yield后面的参数。 yield相关的文章参考 https://zhuanlan.zhihu.com/p/94126166