本博客代码运行环境

     python :     Python 3.7.1rc1   version
pip : pip 19.1.1 version
Scrapy: scrapy 1.6.0 version
asyncio: asyncio 3.4.3 version
aiohttp: aiohttp 3.5.4 version
gevent: gevent 1.4.0 version
grequests: grequests 0.3.0 version
greenlet: greenlet 0.4.15 version
requests: requests 2.21.0 version
urllib3: urllib3 1.24.1 version
tornado: tornado 6.0.2 version
twisted: twisted 19.2.0 version

以下所有代码都以 爬虫 为例, 发送 http 请求,获取页面源码。

概念回顾

操作系统(OS):
是一个用来协调、管理和控制计算机硬件和软件资源的系统程序,它位于硬件和应用程序之间。
进程(Process):------------》》是 OS 进行资源分配和调度的一个基本独立单位
进程就是一个程序在一个数据集上的一次动态执行过程。
进程一般由程序、数据集、进程控制块三部分组成。
程序: 由我们编写用来描述进程要完成哪些功能以及如何完成,是指令、数据及其组织形式的描述,进程是程序的实体
数据集: 则是程序在执行过程中所需要使用的资源;
进程控制块: 用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。
多进程:
指操作系统能同时运行多个任务(程序)。
总结来说:
     进程是线程的容器
每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位
适用于: 计算密集型

线程(Thread):------------》》是cpu调度和分派的最小单位
  有时被称为轻量级进程(Lightweight Process,LWP)

为了降低上下文切换的消耗,提高系统的并发性,并突破一个进程只能干一样事的缺陷,使到进程内并发成为可能。
是程序执行流的最小单元。 一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成
线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。
由于线程之间的相互制约,致使线程在运行中呈现出间断性。
线程也有就绪、阻塞和运行三种基本状态
就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待 CPU 调度;
阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
运行状态是指线程占有 CPU 正在运行;
多线程:
在单个程序中同时运行多个线程完成不同的工作,即具有多个顺序流在执行。
  总结来说:
线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。
同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)
适用于: IO 密集型
GIL全局解释器锁(Global Interpreter Lock):
无论你启多少个线程,你有多少个cpu, Python在执行一个进程的时候会淡定的在同一时刻只允许一个线程运行
机制,一个基本的要求就是需要实现不同线程对共享资源访问的互斥,所以引入了GIL。
GIL缺点:多处理器退化为单处理器;优点:避免大量的加锁解锁操作
协程(Coroutine):
又称微线程,纤程。协程是一种用户态的轻量级线程。
线程/进程:操作系统提供的一种并发处理任务的能力,操作是由程序触发系统接口, 操作者:系统;
协程:程序员通过高超的代码能力,在代码执行流程中人为的实现多任务并发,是单个线程内的任务调度技巧。操作者:程序员;
没有切换的开销。协程不需要多线程的锁机制,因为都是在同一个线程中运行,所以没有同时访问数据的问题,执行效率比多线程高很多
协程存在的意义:对于多线程应用,CPU通过切片(轮询)的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。
协程切换时,因为只使用一个线程,是由程序自身控制的,体现的是程序员的流程控制能力,通过一定的语法规定在一个线程中所有代码块的执行顺序。
协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程, 即: IO 密集型 综上: 最佳方案: 协程 + 多进程

线程与进程的共同点和区别

(1)共同点:

     线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。

(2)区别:

          线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文。多线程主要是为了充分利用 CPU,提高效率。
线程与进程的区别可以归纳为以下几点:
1)地址空间和其它资源(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。       2)通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。       3)调度和切换:线程上下文切换比进程上下文切换要快得多。故所消耗的资源比进程要少的多多。       4)在多线程OS中,进程不是一个可执行的实体。
(3)线程的属性(特点):
1)轻型实体
      线程中的实体基本上不拥有系统资源,只是有一点必不可少的、能保证独立运行的资源,比如:
在每个线程中都具有一个用于控制线程运行的线程控制块TCB,用于指示被执行指令序列的程序计数器、保留局部变量、少数状态参数和返回地址等的一组寄存器和堆栈。     2)独立调度和分派的基本单位。
      在多线程OS中,线程是能独立运行的基本单位,因而也是独立调度和分派的基本单位。由于线程很“轻”,故线程的切换非常迅速且开销小。     3)可并发执行。
      在一个进程中的多个线程之间,可以并发执行,甚至允许在一个进程中所有线程都能并发执行;同样,不同进程中的线程也能并发执行。     4)共享进程资源。
      在同一进程中的各个线程,都可以共享该进程所拥有的资源,这首先表现在:
所有线程都具有相同的地址空间(进程的地址空间),这意味着,线程可以访问该地址空间的每一个虚地址;此外,还可以访问进程所拥有的已打开文件、定时器、信号量机构等。

HTTP 协议

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。

HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。

HTTP是一个属于应用层的面向对象的协议,目前在WWW中使用的是 HTTP/1.0的第六版,

HTTP协议工作于客户端-服务端架构为上。基于 : 请求-----响应 ,模式

HTTP 特点

1、简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。
每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。 2、灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。 3.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。 4.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。
缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

HTTP 协议 数据发送格式

HTTP 请求协议

请求首行;         // 请求方式 请求路径 协议和版本,例如:GET /index.html HTTP/1.1
请求头信息; // 请求头名称:请求头内容,即为key:value格式,例如:Host:localhost
空行; // 用与分隔 请求头 和 请求体(\r\n\r\n)
请求体。 // GET没有请求体,只有POST有请求体。
GET:
HTTP默认的请求方法就是GET
      * 没有请求体
      * 数据量有限制!
      * GET请求数据会暴露在浏览器的地址栏中
GET请求常用的操作:
       1. 在浏览器的地址栏中直接给出URL,那么就一定是GET请求
       2. 点击页面上的超链接也一定是GET请求
       3. 提交表单时,表单默认使用GET请求,但可以设置为POST
例如:
GET 请求:
GET /338.jpg HTTP/1.1\r\nHost:img.mukewang.com\r\nContent-Type:multipart/form-data\r\nReferer:http://www.imooc.com/\r\n\r\n
POST 请求:
POST / HTTP/1.1\r\nHost: img.mukewang.com\r\nConnection: Keep-Alive\r\n\r\nname=Professional&publisher=Wiley

请求头:

1、Host

请求的web服务器域名地址

2、User-Agent

HTTP客户端运行的浏览器类型的详细信息。通过该头部信息,web服务器可以判断出http请求的客户端的浏览器的类型。

3、Accept

指定客户端能够接收的内容类型,内容类型的先后次序表示客户都接收的先后次序

4、Accept-Lanuage

指定HTTP客户端浏览器用来展示返回信息优先选择的语言

5、Accept-Encoding

指定客户端浏览器可以支持的web服务器返回内容压缩编码类型。表示允许服务器在将输出内容发送到客户端以前进行压缩,以节约带宽。
而这里设置的就是客户端浏览器所能够支持的返回压缩格式。 6、Accept-Charset HTTP客户端浏览器可以接受的字符编码集 7、Content-Type 显示此HTTP请求提交的内容类型。一般只有post提交时才需要设置该属性 有关Content-Type属性值有如下两种编码类型: (1)“application/x-www-form-urlencoded”: 表单数据向服务器提交时所采用的编码类型,默认的缺省值就是“application/x-www-form-urlencoded”。
然而,在向服务器发送大量的文本、包含非ASCII字符的文本或二进制数据时这种编码方式效率很低。 (2)“multipart/form-data”: 在文件上载时,所使用的编码类型应当是“multipart/form-data”,它既可以发送文本数据,也支持二进制数据上载。 当提交为表单数据时,可以使用“application/x-www-form-urlencoded”;当提交的是文件时,就需要使用“multipart/form-data”编码类型。

HTTP 响应协议

HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。
例如:
HTTP/1.1 200 OK
Date: Fri, 22 May 2009 06:07:21 GMT
Content-Type: text/html; charset=UTF-8 <html>
<head></head>
<body>
<!--body goes here-->
</body>
</html>

例:

HTTP/1.1 200 OK\r\nDate:Fri, 22 May 2009 06:07:21 GMT\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n<html><head</head><body>shiwei</body></html>

第一部分:状态行,由HTTP协议版本号, 状态码, 状态消息 三部分组成。

第一行为状态行,(HTTP/1.1)表明HTTP版本为1.1版本,状态码为200,状态消息为(ok)

第二部分:消息报头,用来说明客户端要使用的一些附加信息

第二行和第三行为消息报头,
              Date:生成响应的日期和时间;Content-Type:指定了MIME类型的HTML(text/html),编码类型是UTF-8

第三部分:空行,消息报头后面的空行是必须的
第四部分:响应正文,服务器返回给客户端的文本信息。

响应状态码:

状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:
1xx:指示信息--表示请求已接收,继续处理
2xx:成功--表示请求已被成功接收、理解、接受
3xx:重定向--要完成请求必须进行更进一步的操作
4xx:客户端错误--请求有语法错误或请求无法实现
5xx:服务器端错误--服务器未能实现合法的请求
常见状态码:
200 OK //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常

准备好了吗?基础知识很重要!!

编写爬虫程序,性能的消耗主要在 IO 请求中,当单进程单线程模式下请求URL时必然会引起等待,效率极低!

 import requests

 def task(url):
response = requests.get(url)
return response url_list = ['http://www.github.com', 'http://www.bing.com'] for url in url_list:
task(url)

同步执行

 from concurrent.futures import ThreadPoolExecutor
import requests def task(url):
response = requests.get(url)
print(response)
# print(response.text) # 获取 页面 源码 字符串数据
print("\033[1;30;47murl==%-70s----------response==%-s\033[0m"%(url,response.status_code))
return response url_list = [
"http://tuijian.hao123.com/",
"http://www.163.com/",
"http://www.eastmoney.com/",
] pool = ThreadPoolExecutor(5) for url in url_list:
v = pool.submit(task,url) pool.shutdown(wait=True)

多线程执行

from concurrent.futures import ThreadPoolExecutor
import requests def task(url):
""" 返回页面 源码数据 """
response = requests.get(url)
print("\033[1;30;47murl==%-70s----------response==%-s\033[0m"%(url,response.status_code))
return response def done(future,*args, **kwargs):
""" 解析页面 源码 """
print(future.result()) url_list = [
"http://tuijian.hao123.com/",
"http://www.163.com/",
"http://www.eastmoney.com/",
] pool = ThreadPoolExecutor(5) for url in url_list:
v = pool.submit(task,url)
v.add_done_callback(done) pool.shutdown(wait=True)

多线程 + 回调函数 

from concurrent.futures import ProcessPoolExecutor
import requests pool = ProcessPoolExecutor(5)
def task(url):
response = requests.get(url)
print(response)
print("\033[1;30;47murl==%-70s----------response==%-s\033[0m"%(url,response.status_code))
return response url_list = [
"http://tuijian.hao123.com/",
"http://www.163.com/",
"http://www.eastmoney.com/",
] if __name__ == "__main__": # 必须要加 此 判断语句
for url in url_list:
v = pool.submit(task, url) pool.shutdown(wait=True)

多进程执行

from concurrent.futures import ProcessPoolExecutor
import requests
pool = ProcessPoolExecutor(5) def task(url):
response = requests.get(url)
# print("\033[1;30;47murl==%-70s----------response==%-s\033[0m"%(url,response.status_code))
return response def done(*args, **kwargs):
print(args[0].result())
print("\033[1;31;40m %s-----%s \033[0m"%(args, kwargs))
url_list = [
"http://tuijian.hao123.com/",
"http://www.163.com/",
"http://www.eastmoney.com/",
] if __name__ == "__main__": # 必须要加 此 判断语句
for url in url_list:
v = pool.submit(task, url)
v.add_done_callback(done) pool.shutdown(wait=True)

多进程 + 回调函数

以上代码 均 可提升请求性能, 但多线程 和 多进程 的缺点是 在 IO 阻塞时 依然会造成线程 和 进程的 浪费,

故 异步 IO   是 首选:

遇到 IO , 则 立即转而操作其他, IO 完成时,则自动回调运行处理 IO 的 函数。

import asyncio
# 不支持 HTTP 请求, 但支持 tcp 请求,socket
@asyncio.coroutine # 不可缺少
def task():
print('before ......Task')
yield from asyncio.sleep(5) # 不可写为 time.sleep(5)
print('after ...... Task') tasks = [task(), task(), task()] # 任务列表
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(*tasks))
loop.close()

asyncio 示例

asyncio + 模拟 http :

import asyncio
@asyncio.coroutine
def task(host,url='/'):
# 创建 链接
reader, writer = yield from asyncio.open_connection(host, 80) request_header_content = """GET %s HTTP/1.0\r\nHost: %s\r\n\r\n"""%(url,host,)
request_header_content = bytes(request_header_content, encoding='utf-8') writer.write(request_header_content)
yield from writer.drain()
text = yield from reader.read()
print('ending ',host, url, text)
writer.close() tasks = [
task('www.cnblogs.com', '/wupeiqi/'),
task('www.cnblogs.com', '/shiwei1930/'),
task('www.cnblogs.com', '/alex3714/'),
] loop = asyncio.get_event_loop()
results = loop.run_until_complete(asyncio.gather(*tasks))
loop.close()

asyncio  + aiohttp :

import aiohttp
import asyncio @asyncio.coroutine
def task(url):
print(url)
resp = aiohttp.ClientSession().get(url)
response = yield from resp
print(url, response)
response.close() tasks = [task('http://www.baidu.com/'), task('http://www.chouti.com/')] loop = asyncio.get_event_loop()
results = loop.run_until_complete(asyncio.gather(*tasks))
loop.close()

asyncio + requests

import  requests
import asyncio
@asyncio.coroutine
def task(func,*args):
loop = asyncio.get_event_loop()
future = loop.run_in_executor(None,func,*args)
response = yield from future
print('\033[1;31;40m url=%-30s\n\033[0mcontents=%-30s'%(response.url,response.content)) tasks = [
task(requests.get, 'http://www.baidu.com/'),
task(requests.get, 'http://www.cnblogs.com/'),
task(requests.get, 'http://autohome.com.cn'),
] loop = asyncio.get_event_loop()
results = loop.run_until_complete(asyncio.gather(*tasks))
print(results)
loop.close()

gevent + requests

import requests
import gevent
from gevent import monkey
monkey.patch_all() # 不可缺少 def task(method,url,req_kwargs):
print('method=%s,url=%s,kwargs=%s'%(method,url,req_kwargs))
response = requests.request(method=method,url=url, **req_kwargs)
print('url=%s\n\t\tcontent=%s'%(response.url,response.content)) gevent.joinall([
gevent.spawn(task,method='get', url='https://www.github.com/', req_kwargs={}),
gevent.spawn(task, method='get', url='https://www.yahoo.com/', req_kwargs={}),
gevent.spawn(task, method='get', url='https://www.python.org/', req_kwargs={}),
])

grequests  =    gevent + requests

import grequests

request_list = [
grequests.get('http://www.cnblogs.com/'),
grequests.get('https://www.yahoo.com/'),
grequests.get('https://www.github.com/'),
] response_list = grequests.map(request_list)
print('result=',response_list)
for item in response_list:
print('content=',item.content)

Twisted

from twisted.web.client import getPage,defer
from twisted.internet import reactor def callback(contents):
print(contents) def all_done(arg):
reactor.stop() # 全部完成之后 stop @defer.inlineCallbacks
def task(url):
defered = getPage(bytes(url, encoding='utf8'))
defered.addCallback(callback)
yield defered
defered_list = [] url_list = ['http://www.cnblogs.com/', 'https://github.com/', 'http://baidu.com/']
for url in url_list:
defered = task(url)
defered_list.append(defered) dlist = defer.DeferredList(defered_list)
dlist.addBoth(all_done) # 事件循环
reactor.run() # 去 defered_list 中 检测 谁回来了, 是个死 循环

Tornado

from tornado.httpclient import AsyncHTTPClient
from tornado.httpclient import HTTPRequest
from tornado import ioloop COUNT = 0
def handler_response(response):
global COUNT
COUNT -= 1
if response.error:
print('error:',response.error)
else:
print('body:',response.body)
if COUNT == 0:
ioloop.IOLoop.current().stop() def task():
url_list = [
'http://www.baidu.com/',
'http://www.cnblogs.com/',
'https://www.github.com',
]
global COUNT
COUNT = len(url_list)
for url in url_list:
print("url===",url)
http_client = AsyncHTTPClient()
http_client.fetch(HTTPRequest(url),handler_response)
if __name__ == '__main__':
ioloop.IOLoop.current().add_callback(task)
ioloop.IOLoop.current().start() # # 事件循环, 是一个 死循环

自定义 异步 IO 框架

最基本的 网络编程的 本质:客户端

import socket
sk = socket.socket()
# 链接
sk.connect(('www.baidu.com',80)) # IO 阻塞 # 设置 非阻塞
# sk.setblocking(False) # 请求是 发过去了 print('链接成功!') sk.send(b'GET / HTTP/1.0\r\nHost: baidu.com\r\n\r\n')
# sk.send(b'POST / HTTP/1.0\r\nHost: baidu.com\r\n\r\n fdkfjdkjfkdfj') buffer_size = 1024
# 等待 着 服务端响应
data = sk.recv(buffer_size) # IO 阻塞 print(data)
# 关闭链接
sk.close()

自定义 异步 IO 框架-----》客户端

import select
import socket # IO 多路复用: 监听多个 Socket 对象 ,死循环, 事件循环
# - 利用此特性 可以开发 异步 IO 模块 等等 # 异步 IO : 遇到 IO , 则 立即转而操作其他, IO 返回时,则自动回调处理 IO 的 函数。
# 回答: 非阻塞的 socket(setblocking(False)) + IO 多路复用 # 此时 为客户端
class HttpRequest:
def __init__(self, sk, host, callback):
self.socket = sk
self.host = host
self.callback = callback
def fileno(self):
return self.socket.fileno() Buffer_size = 4096 class HttpResponse:
def __init__(self, recv_data):
self.recv_data = recv_data
self.header_dict = {}
self.body = ""
self.initialize() def initialize(self):
headers, body = self.recv_data.split(b'\r\n\r\n', 1)
header_list = headers.split(b'\r\n')
for item in header_list:
item_str = str(item, encoding='utf-8')
sp = item_str.split(':', 1)
if len(sp) == 2:
self.header_dict[sp[0]] = sp[1] class AsyncRequest:
def __init__(self):
self.conn = []
self.connection = [] # 用于检测 是否链接成功 def add_request(self, host,callback):
try:
sk = socket.socket()
sk.setblocking(False)
sk.connect((host, 80))
except BlockingIOError as e:
pass
request = HttpRequest(sk, host, callback)
self.conn.append(request)
self.connection.append(request) def run(self):
# 事件 循环
while True:
rlist, wlist, elist = select.select(self.conn, self.connection, self.conn, 0.05)
for w in wlist:
print(w.host,'链接成功')
# 表示 socket 和服务端链接 成功
txt = "GET / HTTP/1.0\r\nHost:%s\r\n\r\n"%(w.host)
w.socket.send(bytes(txt, encoding='utf8'))
self.connection.remove(w)
print('write over')
for r in rlist:
print(r.host, '有数据返回 ')
# r = HttpRequest object
recv_data = bytes()
while True:
try:
chunck = r.socket.recv(Buffer_size)
recv_data += chunck
except Exception as e:
break response = HttpResponse(recv_data) r.callback(response)
print('host=%s,返回数据为: recv_data=%s'%(r.host,recv_data))
self.conn.remove(r) if not self.conn:
break self.connection
self.conn def f1(response):
print('保存到文件,', response.header_dict)
def f2(response):
print('保存到数据库,', response.header_dict)
url_list = [
# 'cn.bing.com',
{"host": 'www.baidu.com', 'callback': f1},
{'host': 'www.cnblogs.com', 'callback': f2},
] req = AsyncRequest()
for item in url_list:
req.add_request(item['host'], item['callback']) req.run() # 等待 服务端的 链接成功 信号

Web 请求之--性能相关的更多相关文章

  1. ANTS Performance Profiler 8:支持对Web请求、异步代码和WinRT的性能剖析

    下载与激活:http://download.csdn.net/detail/lone112/6734291 离线激活   位于英国的Red Gate Software有限公司最近发布了ANTS Per ...

  2. benchmark pm2的cluster模式发布web app的性能与相关问题解决方法

    pm2以cluster集群方式发布app,可以高效地利用多核cpu,有效提升吞吐量.在上周对公司的redmine服务器进行性能调优后,深感ruby on rails的性能低下,这次测试nodejs的s ...

  3. H5 缓存机制浅析 移动端 Web 加载性能优化

    腾讯Bugly特约作者:贺辉超 1 H5 缓存机制介绍 H5,即 HTML5,是新一代的 HTML 标准,加入很多新的特性.离线存储(也可称为缓存机制)是其中一个非常重要的特性.H5 引入的离线存储, ...

  4. Http协议简单解析及web请求过程

    HTTP协议: HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统. 基于HTTP协议的客户端/服务器请求响应机制的信息交换过程包含下面几个步骤: 1)    ...

  5. 高性能MySQL第2,3章性能相关 回顾笔记

    1.  基准测试(benchmark)   不管是新手还是专家都要熟悉基准测试,benchmark测试是对系统的一种压力测试,目标是为了掌握在特定压力下系统的行为.也有其他原因:如重现系统状态,或者是 ...

  6. 与JavaWeb有关的故事(web请求与Java I/O)

    作为一名后端屌丝程序员,对算法.并发.性能乐此不疲.但是,随着年龄和阅历的增加,显然叶落而不知秋的心态是不太能混了.尤其是,某T面试官在明知我是后端,且明确表示对HTTP协议不太熟的情况下,强行让我解 ...

  7. Python 爬虫性能相关

    性能相关 在编写爬虫时,性能的消耗主要在IO请求中,当单进程单线程模式下请求URL时必然会引起等待,从而使得请求整体变慢. import requests def fetch_async(url): ...

  8. 007-优化web请求三-异步调用【WebAsyncTask】

    一.什么是同步调用 浏览器发起请求,Web服务器开一个线程处理,处理完把处理结果返回浏览器.好像没什么好说的了,绝大多数Web服务器都如此般处理.现在想想如果处理的过程中需要调用后端的一个业务逻辑服务 ...

  9. 《深入分析Java Web技术内幕》读书笔记 - 第1章 深入Web请求过程

    第1章 深入Web请求过程 1 1.1 B/S网络架构概述 2 基于统一的应用层协议HTTP来交互数据. 1.2 如何发起一个请求 4 HTTP连接本质是建立Socket连接.请求实现方式:工具包如H ...

随机推荐

  1. Python3.5-20190530-unittest模块

    >>> dir(unittest) #所有的属性和方法 ['BaseTestSuite', 'FunctionTestCase', 'SkipTest', 'TestCase', ' ...

  2. Flutter pubspec.yaml配置文件

    name: flutter_app1 # 应用名称 description: A new Flutter application. # 应用描述 # The following defines the ...

  3. Web前端性能优化详解之CSS与JS加载

    浏览器加载页面和渲染过程 加载过程 浏览器根据DNS 服务器得到域名的IP地坛 向这个 IP 的机器发送 HTTP请求 服务器收到,处理并返回 HTTP请求 浏览器得到返回内容 渲染过程 根据 HTM ...

  4. 21.使用LinkedBlockingQueue模拟生产者与消费者

    import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import java.util.co ...

  5. SOA架构是什么?

    https://blog.csdn.net/u013343616/article/details/79460398 SOA是什么?SOA全英文是Service-Oriented Architectur ...

  6. JavaScript之ECMAScript

    JavaScript脚本语言, 运行在浏览器上,无需编译, 轻量级的语言. 功能:让页面有执行逻辑的功能, 可以产生一些动态的效果 JavaScript = ECMAScript + BOM + DO ...

  7. Linux 统计文件夹下文件个数及目录个数

    1. 统计文件夹下文件的个数 ls -l | grep "^-" | wc -l 2.统计文件夹下目录的个数 ls -l | grep "^d" | wc -l ...

  8. Unity编程标准导引-1.1下载和安装Unity

    本文为博主原创文章,欢迎转载,请保留出处:http://blog.csdn.net/andrewfan 1.1.下载和安装Unity 1.1.1 选取版本 首先找到Unity官方网站https://s ...

  9. [CSP-S模拟测试]:z(模拟+map+小根堆)

    题目背景 $\frac{1}{4}$遇到了一道水题,$eooooo$完全不会做,于是去请教小$D$.结果小$D$已经去了阿塞拜疆,于是,$\frac{1}{4}$只好来问你,这道题是这样的: 题目描述 ...

  10. Linux配置Selenium+Chrome+Python

    ---恢复内容开始--- 最近一个月没有更新博客了.最近都在复习LINUX与PYTHON知识.决定以后在LINUX环境下学习新知识. 包括后期的框架学习与平台知识方面. 直接记录今天下午的学习成果. ...