当前位置: 首页 > news >正文

Python高性能编程

 一、进程池和线程池

1.串行

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

import time

import requests

url_lists = [

    'http://www.baidu.com',

    'http://fanyi.baidu.com',

    'http://map.baidu.com',

    'http://music.baidu.com/',

    'http://tieba.baidu.com',

    'http://v.baidu.com',

    'http://image.baidu.com',

    'http://zhidao.baidu.com',

    'http://news.baidu.com',

    'http://xueshu.baidu.com']

start_time = time.time()

for url in url_lists:

    response = requests.get(url)

    print(response.text)

print("Runtime: {}".format(time.time()-start_time))

# Runtime: 1.95

  

2.多进程

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

import time

import requests

from multiprocessing import Process

url_lists = [

    'http://www.baidu.com',

    'http://fanyi.baidu.com',

    'http://map.baidu.com',

    'http://music.baidu.com/',

    'http://tieba.baidu.com',

    'http://v.baidu.com',

    'http://image.baidu.com',

    'http://zhidao.baidu.com',

    'http://news.baidu.com',

    'http://xueshu.baidu.com']

def task(url):

    response = requests.get(url)

    print(response.text)

if __name__ == '__main__':

    p_list = []

    start_time = time.time()

    for url in url_lists:

        p = Process(target=task, args=(url,))

        p_list.append(p)

        p.start()

    for in p_list:

        p.join()

    print("Runtime: {}".format(time.time() - start_time))

# Runtime: 1.91

 

3.进程池(1)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

import time

import requests

from concurrent.futures import ProcessPoolExecutor

"""

Py2里    没有线程池   但是有进程池

Py3里    有线程池     有进程池

"""

url_lists = [

    'http://www.baidu.com',

    'http://fanyi.baidu.com',

    'http://map.baidu.com',

    'http://music.baidu.com/',

    'http://tieba.baidu.com',

    'http://v.baidu.com',

    'http://image.baidu.com',

    'http://zhidao.baidu.com',

    'http://news.baidu.com',

    'http://xueshu.baidu.com']

def task(url):

    response = requests.get(url)

    print(response.content)

if __name__ == '__main__':

    start_time = time.time()

    pool = ProcessPoolExecutor(10)

    for url in url_lists:

        pool.submit(task,url)

    pool.shutdown(wait=True)

    print("Runtime: {}".format(time.time() - start_time))

# Runtime: 2.00

  

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

# 进程池 + 回调函数

import time

import requests

from concurrent.futures import ProcessPoolExecutor

"""

Py2里    没有线程池   但是有进程池

Py3里    有线程池     有进程池

"""

url_lists = [

    'http://www.baidu.com',

    'http://fanyi.baidu.com',

    'http://map.baidu.com',

    'http://music.baidu.com/',

    'http://tieba.baidu.com',

    'http://v.baidu.com',

    'http://image.baidu.com',

    'http://zhidao.baidu.com',

    'http://news.baidu.com',

    'http://xueshu.baidu.com']

def task(url):

    response = requests.get(url)

    return response.content

def callback(future):

    print(future.result())

if __name__ == '__main__':

    start_time = time.time()

    pool = ProcessPoolExecutor(10)

    for url in url_lists:

        v = pool.submit(task,url)

        v.add_done_callback(callback)

    pool.shutdown(wait=True)

    print("Runtime: {}".format(time.time() - start_time))

  

3.进程池(2)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

import time

import requests

from  multiprocessing import Pool

url_lists = [

    'http://www.baidu.com',

    'http://fanyi.baidu.com',

    'http://map.baidu.com',

    'http://music.baidu.com/',

    'http://tieba.baidu.com',

    'http://v.baidu.com',

    'http://image.baidu.com',

    'http://zhidao.baidu.com',

    'http://news.baidu.com',

    'http://xueshu.baidu.com']

def task(url):

    response = requests.get(url)

    return response.content

def callBackFunc(content):

    print(content)

if __name__ == '__main__':

    start_time = time.time()

    pool = Pool(10)

    for url in url_lists:

        pool.apply_async(func=task,args=(url,),callback=callBackFunc)

    pool.close()

    pool.join()

    print("Runtime: {}".format(time.time() - start_time))

# Runtime: 1.96

 

2019-03-06 補充

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

# Parallel 底层調用的是 multiprocessing

import time

from joblib import Parallel, delayed

def func(idx):

    print(idx)

    time.sleep(1)

    return {'idx':idx}

start_ts = time.time()

results = Parallel(-1)(

    delayed(func)(x) for in range(4)

)

print(results)

print('Runtime : {}'.format(time.time()-start_ts))

4.多线程

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

import time

import requests

from threading import Thread

url_lists = [

    'http://www.baidu.com',

    'http://fanyi.baidu.com',

    'http://map.baidu.com',

    'http://music.baidu.com/',

    'http://tieba.baidu.com',

    'http://v.baidu.com',

    'http://image.baidu.com',

    'http://zhidao.baidu.com',

    'http://news.baidu.com',

    'http://xueshu.baidu.com']

def task(url):

    response = requests.get(url)

    print(response.text)

if __name__ == '__main__':

    t_list = []

    start_time = time.time()

    for url in url_lists:

        t = Thread(target=task, args=(url,))

        t_list.append(t)

        t.start()

    for in t_list:

        t.join()

    print("Runtime: {}".format(time.time() - start_time))

# Runtime: 0.49

  

5.线程池

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

import time

import requests

from concurrent.futures import ThreadPoolExecutor

"""

Py2里    没有线程池   但是有进程池

Py3里    有线程池     有进程池

"""

url_lists = [

    'http://www.baidu.com',

    'http://fanyi.baidu.com',

    'http://map.baidu.com',

    'http://music.baidu.com/',

    'http://tieba.baidu.com',

    'http://v.baidu.com',

    'http://image.baidu.com',

    'http://zhidao.baidu.com',

    'http://news.baidu.com',

    'http://xueshu.baidu.com']

def task(url):

    response = requests.get(url)

    print(response.content)

if __name__ == '__main__':

    start_time = time.time()

    pool = ThreadPoolExecutor(10)

    for url in url_lists:

        pool.submit(task,url)

    pool.shutdown(wait=True)

    print("Runtime: {}".format(time.time() - start_time))

# Runtime: 0.51

  

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

# 线程池 + 回调函数

import time

import requests

from concurrent.futures import ThreadPoolExecutor

"""

Py2里    没有线程池   但是有进程池

Py3里    有线程池     有进程池

"""

url_lists = [

    'http://www.baidu.com',

    'http://fanyi.baidu.com',

    'http://map.baidu.com',

    'http://music.baidu.com/',

    'http://tieba.baidu.com',

    'http://v.baidu.com',

    'http://image.baidu.com',

    'http://zhidao.baidu.com',

    'http://news.baidu.com',

    'http://xueshu.baidu.com']

def task(url):

    response = requests.get(url)

    return response.content

def callback(future):

    print(future.result())

if __name__ == '__main__':

    start_time = time.time()

    pool = ThreadPoolExecutor(10)

    for url in url_lists:

        v = pool.submit(task,url)

        v.add_done_callback(callback)

    pool.shutdown(wait=True)

    print("Runtime: {}".format(time.time() - start_time))

  

二、异步非阻塞

1

2

3

4

5

6

7

"""

异步非阻塞/异步IO

    非阻塞: 不等待

      异步: 回调函数

    本质:一个线程完成并发操作(前提是执行过程中一定得有IO,这样才能让线程空闲出来去执行下一个任务)

"""

1.asyncio示例1

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

import asyncio

@asyncio.coroutine

def func1():

    print('before...func1......')

    yield from asyncio.sleep(2)

    print('end...func1......')

@asyncio.coroutine

def func2():

    print('before...func2......')

    yield from asyncio.sleep(1)

    print('end...func2......')

@asyncio.coroutine

def func3():

    print('before...func3......')

    yield from asyncio.sleep(3)

    print('end...func3......')

tasks = [func1(), func2(), func3()]

loop = asyncio.get_event_loop()

loop.run_until_complete(asyncio.gather(*tasks))

loop.close()

### 结果 ###

before...func3......

before...func2......

before...func1......

end...func2......

end...func1......

end...func3......

2.asyncio示例2

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

####################################################################################

# async/await 是 python3.5中新加入的特性,将异步从原来的yield 写法中解放出来,变得更加直观;

# async 写在def前,替代了装饰器@asyncio.coroutine;await 替换了yield from;

####################################################################################

import asyncio

async def func1():

    print('before...func1......')

    await asyncio.sleep(2)

    print('end...func1......')

async def func2():

    print('before...func2......')

    await asyncio.sleep(1)

    print('end...func2......')

async def func3():

    print('before...func3......')

    await asyncio.sleep(3)

    print('end...func3......')

tasks = [func1(), func2(), func3()]

loop = asyncio.get_event_loop()

loop.run_until_complete(asyncio.gather(*tasks))

loop.close()

  

3.asyncio示例3

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

import asyncio

@asyncio.coroutine

def fetch_async(host, url='/'):

    print(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(host, url, text)

    writer.close()

task_list = [

    fetch_async('www.cnblogs.com''/standby/'),

    fetch_async('www.cnblogs.com''/standby/p/7739797.html'),

    fetch_async('www.cnblogs.com''/wupeiqi/articles/6229292.html')

]

loop = asyncio.get_event_loop()

results = loop.run_until_complete(asyncio.gather(*task_list))

loop.close()

  

4.asyncio+aiohttp示例1

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

import asyncio

import aiohttp

import async_timeout

async def fetch(session, url):

    with async_timeout.timeout(10):

        async with session.get(url) as response:

            return await response.text()

async def fetch_async(url):

    async with aiohttp.ClientSession() as session:

        html = await fetch(session, url)

        print(html)

tasks = [

    fetch_async('https://api.github.com/events'),

    fetch_async('http://aiohttp.readthedocs.io/en/stable/'),

    fetch_async('http://aiohttp.readthedocs.io/en/stable/client.html')]

event_loop = asyncio.get_event_loop()

results = event_loop.run_until_complete(asyncio.gather(*tasks))

event_loop.close()

或者

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

import asyncio

import aiohttp

import async_timeout

async def fetch_async(url):

    async with aiohttp.ClientSession() as session:

        with async_timeout.timeout(10):

            async with session.get(url) as resp:

                print(resp.status)

                print(await resp.text())

tasks = [

    fetch_async('https://api.github.com/events'),

    fetch_async('http://aiohttp.readthedocs.io/en/stable/'),

    fetch_async('http://aiohttp.readthedocs.io/en/stable/client.html')]

event_loop = asyncio.get_event_loop()

results = event_loop.run_until_complete(asyncio.gather(*tasks))

event_loop.close()

5.asyncio+requests示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

import asyncio

import requests

@asyncio.coroutine

def fetch_async(func, *args):

    loop = asyncio.get_event_loop()

    future = loop.run_in_executor(None, func, *args)

    response = yield from future

    print(response.url, response.content)

tasks = [

    fetch_async(requests.get'http://aiohttp.readthedocs.io/en/stable/'),

    fetch_async(requests.get'https://api.github.com/events')

]

loop = asyncio.get_event_loop()

results = loop.run_until_complete(asyncio.gather(*tasks))

loop.close()

补充:

1

2

3

4

5

有时候会遇到 RuntimeError: Event loop is closed 这个错误

参考:https://stackoverflow.com/questions/45600579/asyncio-event-loop-is-closed

在 fetch_async 函数里添加一下语句即可

asyncio.set_event_loop(asyncio.new_event_loop())

6.gevent+requests示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

import gevent

import requests

from gevent import monkey

from gevent.pool import Pool

monkey.patch_all()

def fetch_async(method, url, req_kwargs):

    print(method, url, req_kwargs)

    response = requests.request(method=method, url=url, **req_kwargs)

    print(response.url, response.content)

# ##### 发送请求 #####

# gevent.joinall([

#     gevent.spawn(fetch_async, method='get', url='https://www.python.org/', req_kwargs={}),

#     gevent.spawn(fetch_async, method='get', url='https://www.yahoo.com/', req_kwargs={}),

#     gevent.spawn(fetch_async, method='get', url='https://github.com/', req_kwargs={}),

#     gevent.spawn(fetch_async, method='get', url='https://api.github.com/events', req_kwargs={}),

# ])

# ##### 发送请求(协程池控制最大协程数量) #####

# pool = Pool(None)

pool = Pool(3)

gevent.joinall([

    pool.spawn(fetch_async, method='get', url='https://www.python.org/', req_kwargs={}),

    pool.spawn(fetch_async, method='get', url='https://www.yahoo.com/', req_kwargs={}),

    pool.spawn(fetch_async, method='get', url='https://www.github.com/', req_kwargs={}),

    pool.spawn(fetch_async, method='get', url='https://api.github.com/events', req_kwargs={}),

    pool.spawn(fetch_async, method='get', url='https://www.baidu.com', req_kwargs={}),

    pool.spawn(fetch_async, method='get', url='https://www.ibm.com', req_kwargs={}),

    pool.spawn(fetch_async, method='get', url='https://www.intel.com', req_kwargs={}),

    pool.spawn(fetch_async, method='get', url='https://www.iqiyi.com', req_kwargs={}),

])

使用gevent协程并获取返回值示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

def get_single_chart_data_flux(single_data_param):

    import gevent

    from gevent import monkey

    from gevent.pool import Pool as gPool

    monkey.patch_socket()

    ip,port,timestamp,time_length,type_name,subtype_name,filter_str_list,appid,legend = single_data_param

    ModelClass = get_model_class(type_name)

    func = apps.get_app_config('serverdata').service.get_single_chart_data

    pool = gPool(len(filter_str_list))

    func_li = []

    for filter_str in filter_str_list:

        func_li.append(pool.spawn(func,ModelClass,ip,port,timestamp,time_length,subtype_name,filter_str,appid,legend))

    ret_li = gevent.joinall(func_li)

    # view_logger.debug(ret_li[0].get('value'))

    result_li = [{'filter_con':item.get('value')[2], 'value':item.get('value')[1], 'legend':item.get('value')[3]} for item in ret_li]

    return result_li

7.Twisted示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

from twisted.web.client import getPage, defer

from twisted.internet import reactor

def all_done(arg):

    reactor.stop()

def callback(contents,url):

    print(url,contents)

deferred_list = []

url_list = [

    'http://www.bing.com',

    'http://www.baidu.com',

    'https://www.python.org',

    'https://www.yahoo.com',

    'https://www.github.com'

]

start_time = time.time()

for url in url_list:

    deferred = getPage(bytes(url, encoding='utf8'))

    deferred.addCallback(callback,url)

    deferred_list.append(deferred)

dlist = defer.DeferredList(deferred_list)

dlist.addBoth(all_done)

reactor.run()

8.Tornado示例

以上均是Python内置以及第三方模块提供异步IO请求模块,使用简便大大提高效率;

而对于异步IO请求的本质则是【非阻塞Socket】+【IO多路复用】 

三、自定义异步非阻塞模块

1.简单示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

"""

异步非阻塞/异步IO

    非阻塞: 不等待

      异步: 回调函数

    本质:一个线程完成并发操作(前提是执行过程中一定得有IO,这样才能让线程空闲出来去执行下一个任务)

     

     

IO 多路复用  +  socket

    - IO多路复用:  select epoll 用于检测socket对象是否发生变化(是否连接成功,是否有数据到来)

    - socket  :  socket客户端

     

    - IO请求是不占用CPU的,计算型的才占用CPU

"""

import socket

import select

conn_list = []

input_list = []

for url in range(20):

    client = socket.socket()

    client.setblocking(False)

    try:

        client.connect(('61.135.169.121',80))

    except BlockingIOError as e:

        pass

    conn_list.append(client)

    input_list.append(client)

while True:

    rlist, wlist, errlist = select.select(input_list, conn_list, [], 0.05)

    for sock in wlist:

        sock.sendall(b"GET / HTTP/1.0\r\nHost: www.baidu.com\r\n\r\n")

        conn_list.remove(sock)

    for sock in rlist:

        data = sock.recv(8192)

        sock.close()

        input_list.remove(sock)

        print(data)

    if not input_list:

        break

2.自定义异步非阻塞模块

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

#!/usr/bin/python3.5

# -*- coding:utf-8 -*-

"""

异步非阻塞/异步IO

    非阻塞: 不等待

      异步: 回调函数

    本质:一个线程完成并发操作(前提是执行过程中一定得有IO,这样才能让线程空闲出来去执行下一个任务)

     

     

IO 多路复用  +  socket

    - IO多路复用:  select epoll 用于检测socket对象是否发生变化(是否连接成功,是否有数据到来)

    - socket  :  socket客户端

     

    - IO请求是不占用CPU的,计算型的才占用CPU

"""

import socket

import select

from urllib import parse

class Request():

    def __init__(self,sock,url,callback):

        """

        初始化

        :param sock: client's socket

        :param callback: callback function

        :param url: page url which wanna crawling

        """

        self.sock = sock

        self.url = url

        self.callback = callback

    def fileno(self):

        return self.sock.fileno()

    @property

    def host(self):

        domain = parse.urlparse(self.url)

        return domain.netloc

    @property

    def pathinfo(self):

        domain = parse.urlparse(self.url)

        return domain.path

def async_request(url_list):

    conn_list = []

    input_list = []

    for li in url_list:

        sock = socket.socket()

        sock.setblocking(False)

        obj = Request(sock, li[0], li[1])

        try:

            sock.connect((obj.host,80))

        except BlockingIOError as e:

            pass

        conn_list.append(obj)

        input_list.append(obj)

    while True:

        # 监听socket是否已经发生变化 [request_obj,request_obj....request_obj]

        # 如果有请求连接成功:wlist = [request_obj,request_obj]

        # 如果有响应的数据:  rlist = [request_obj,request_obj....client100]

        rlist, wlist, errlist = select.select(input_list, conn_list, [], 0.05)

        for obj in wlist:

            # print("链接成功,发送请求...")

            # obj.sock.sendall("GET {0} HTTP/1.0\r\nHost: {1}\r\n\r\n".format(obj.pathinfo,obj.host).encode('utf-8'))

            obj.sock.sendall(bytes("GET {0} HTTP/1.0\r\nHost: {1}\r\n\r\n".format(obj.pathinfo,obj.host),encoding='utf-8'))

            conn_list.remove(obj)

        for obj in rlist:

            # print("获取响应...")

            data = obj.sock.recv(8192)

            obj.callback(data)

            obj.sock.close()

            input_list.remove(obj)

        if not input_list:

            break

if __name__ == '__main__':

    def callback1(data):

        print("cnblogs...", data)

    def callback2(data):

        print("csdn...", data)

    def callback3(data):

        print("tornadoweb...", data)

    url_list = [

        ['http://www.cnblogs.com/standby/p/7589055.html', callback1],

        ['http://www.cnblogs.com/wupeiqi/articles/6229292.html', callback1],

        ['http://blog.csdn.net/vip_wangsai/article/details/51997882', callback2],

        ['http://blog.csdn.net/hjhmpl123/article/details/53378068', callback2],

        ['http://blog.csdn.net/zcc_0015/article/details/50688145', callback2],

        ['http://www.tornadoweb.org/en/stable/guide.html', callback3],

        ['http://www.tornadoweb.org/en/stable/guide/async.html', callback3],

        ['http://www.tornadoweb.org/en/stable/guide/coroutines.html#python-3-5-async-and-await', callback3]

    ]

    async_request(url_list)

  

3.牛逼的异步IO模块

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

import select

import socket

import time

class AsyncTimeoutException(TimeoutError):

    """

    请求超时异常类

    """

    def __init__(self, msg):

        self.msg = msg

        super(AsyncTimeoutException, self).__init__(msg)

class HttpContext(object):

    """封装请求和相应的基本数据"""

    def __init__(self, sock, host, port, method, url, data, callback, timeout=5):

        """

        sock: 请求的客户端socket对象

        host: 请求的主机名

        port: 请求的端口

        port: 请求的端口

        method: 请求方式

        url: 请求的URL

        data: 请求时请求体中的数据

        callback: 请求完成后的回调函数

        timeout: 请求的超时时间

        """

        self.sock = sock

        self.callback = callback

        self.host = host

        self.port = port

        self.method = method

        self.url = url

        self.data = data

        self.timeout = timeout

        self.__start_time = time.time()

        self.__buffer = []

    def is_timeout(self):

        """当前请求是否已经超时"""

        current_time = time.time()

        if (self.__start_time + self.timeout) < current_time:

            return True

    def fileno(self):

        """请求sockect对象的文件描述符,用于select监听"""

        return self.sock.fileno()

    def write(self, data):

        """在buffer中写入响应内容"""

        self.__buffer.append(data)

    def finish(self, exc=None):

        """在buffer中写入响应内容完成,执行请求的回调函数"""

        if not exc:

            response = b''.join(self.__buffer)

            self.callback(self, response, exc)

        else:

            self.callback(self, None, exc)

    def send_request_data(self):

        content = """%s %s HTTP/1.0\r\nHost: %s\r\n\r\n%s""" % (

            self.method.upper(), self.url, self.host, self.data,)

        return content.encode(encoding='utf8')

class AsyncRequest(object):

    def __init__(self):

        self.fds = []

        self.connections = []

    def add_request(self, host, port, method, url, data, callback, timeout):

        """创建一个要请求"""

        client = socket.socket()

        client.setblocking(False)

        try:

            client.connect((host, port))

        except BlockingIOError as e:

            pass

            # print('已经向远程发送连接的请求')

        req = HttpContext(client, host, port, method, url, data, callback, timeout)

        self.connections.append(req)

        self.fds.append(req)

    def check_conn_timeout(self):

        """检查所有的请求,是否有已经连接超时,如果有则终止"""

        timeout_list = []

        for context in self.connections:

            if context.is_timeout():

                timeout_list.append(context)

        for context in timeout_list:

            context.finish(AsyncTimeoutException('请求超时'))

            self.fds.remove(context)

            self.connections.remove(context)

    def running(self):

        """事件循环,用于检测请求的socket是否已经就绪,从而执行相关操作"""

        while True:

            r, w, e = select.select(self.fds, self.connections, self.fds, 0.05)

            if not self.fds:

                return

            for context in r:

                sock = context.sock

                while True:

                    try:

                        data = sock.recv(8096)

                        if not data:

                            self.fds.remove(context)

                            context.finish()

                            break

                        else:

                            context.write(data)

                    except BlockingIOError as e:

                        break

                    except TimeoutError as e:

                        self.fds.remove(context)

                        self.connections.remove(context)

                        context.finish(e)

                        break

            for context in w:

                # 已经连接成功远程服务器,开始向远程发送请求数据

                if context in self.fds:

                    data = context.send_request_data()

                    context.sock.sendall(data)

                    self.connections.remove(context)

            self.check_conn_timeout()

if __name__ == '__main__':

    def callback_func(context, response, ex):

        """

        :param context: HttpContext对象,内部封装了请求相关信息

        :param response: 请求响应内容

        :param ex: 是否出现异常(如果有异常则值为异常对象;否则值为None)

        :return:

        """

        print(context, response, ex)

    obj = AsyncRequest()

    url_list = [

        {'host''www.google.com''port': 80, 'method''GET''url''/''data''''timeout': 5,

         'callback': callback_func},

        {'host''www.baidu.com''port': 80, 'method''GET''url''/''data''''timeout': 5,

         'callback': callback_func},

        {'host''www.bing.com''port': 80, 'method''GET''url''/''data''''timeout': 5,

         'callback': callback_func},

    ]

    for item in url_list:

        print(item)

        obj.add_request(**item)

    obj.running()

相关文章:

Python高性能编程

一、进程池和线程池 1.串行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import time import requests url_lists [ http://www.baidu.com, http://fanyi.baidu.com, http://map.baidu.com, http://music.baidu.com/, http://tieba.baid…...

MVVM模式下如何正确【视图绑定+数据】

概述 我如何&#xff08;不在后面的代码中使用代码&#xff09;自动绑定到我想要的视图&#xff1f;据我了解&#xff0c;如果正确完成&#xff0c;这就是模式应该如何工作。我可以使用主窗口 xaml 中的代码实现这一切&#xff0c;我甚至正确创建了一个资源字典&#xff08;因…...

外包测试3年,离职后成功入职华为,拿到offer的那天我泪目了....

一提及外包测试&#xff0c;大部分人的第一印象就是&#xff1a;工作强度大&#xff0c;技术含量低&#xff0c;没有归属感&#xff01;外包工作三年总体感受就是这份工作缺乏归属感&#xff0c;心里总有一种落差&#xff0c;进步空间不大&#xff0c;接触不到核心技术&#xf…...

Qt Study

按钮->点击->窗口->关闭窗口 connect(信号的发送者&#xff0c;发送具体信号&#xff0c;信号的接收者&#xff0c;信号的处理); 信号处理函数称为槽 信号槽的优点&#xff0c;松散耦合&#xff0c;信号发送端和接收端本身是没有关联的&#xff0c;通过connect连接…...

JS混淆技术探究及解密方法分析

随着Web技术的快速发展&#xff0c;JavaScript被广泛应用于网页开发、移动应用开发等领域。然而&#xff0c;JavaScript代码很容易被反编译、解密&#xff0c;这给保护网站和应用程序的安全性带来了严重的挑战。为了解决这个问题&#xff0c;JS混淆技术应运而生。JS混淆就是将J…...

智慧制硅厂 Web SCADA 生产线

我国目前是全球最大的工业硅生产国、消费国和贸易国&#xff0c;且未来该产业的主要增量也将来源于我国。绿色低碳发展已成为全球大趋势和国际社会的共识&#xff0c;随着我国“双碳”目标的推进&#xff0c;光伏产业链快速发展&#xff0c;在光伏装机需求的带动下&#xff0c;…...

案例09-数据类型不一致导致equals判断为false

一&#xff1a;背景介绍 在判断课程id和班级id的时候如果一致就像课程信息进行更新&#xff0c;如果不一致就插入一条新的数据。其实两个变量的值是一致的但是类型是不一致的。这就导致数据库中已经有一条这样的数据了&#xff0c;在判断的时候结果为false&#xff0c;就有插入…...

springsecurity中的类

Authentication AuthenticationProvider 每一个AuthenticationProvider对应一个Authentication 很多个AuthenticationProvider 由一个 ProviderManager管理 ProviderManager implements AuthenticationManager 一个ProviderManager有很多个 AuthenticationProvider Usern…...

k8s配置管理

一、configmap 1.1 configmap概述 Configmap 是 k8s 中的资源对象&#xff0c;用于保存非机密性的配置的&#xff0c;数据可以用 key/value 键值对的形式保存&#xff0c;也可通过文件的形式保存。 1.2 configmap作用 我们在部署服务的时候&#xff0c;每个服务都有自己的配置…...

技术官方文档中的代码是用什么展示的?代码高亮插件总结

****内容预警****菜鸟教程***大佬绕道我们经常看到各种技术官方文档&#xff0c;有很多代码展示的区域&#xff0c;用于我们复制粘贴代码&#xff0c;比如vue 的官网当我们需要自己实现这么一个网站的时候&#xff0c;我就开始手忙脚乱&#xff0c;这到底是咋实现的&#xff1f…...

2023年中职组网络安全竞赛——综合渗透测试解析

综合渗透测试 题目如下: PS:需求环境可私信博主,求个三连吧! 解析如下: 通过本地PC中的渗透测试平台KALI2020对服务器场景进行渗透攻击,获取到RSYNC服务所开放的端口,将RSYNC服务开放的端口数值进行MD5加密后作为FLAG提交(如MD5加密前:812);...

【全网最细PAT题解】【PAT乙】1044 火星数字(测试点2,测试点4详细解释)

题目链接 1044 火星数字 题目描述 火星人是以 13 进制计数的&#xff1a;地球人的 0 被火星人称为 tret。 地球人数字 1 到 12 的火星文分别为&#xff1a;jan, feb, mar, apr, may, jun, jly, aug, sep, oct, nov, dec。 火星人将进位以后的 12 个高位数字分别称为&#xff1a…...

rsync+xinetd+inotify+sersync

一、介绍 1.1、rsync 对比 scp 相同&#xff1a; 都有拷贝的功能不同&#xff1a; rsync:具有增量复制&#xff0c;每次复制的时候&#xff0c;会扫描对端是否在同路径下有我要发送的一样的文件或者目录&#xff0c;如果&#xff0c;如果存在&#xff0c;则不进行复制。边复制&…...

CSS - 扫盲

文章目录1. 前言2. CSS2.1 css 的引入方式2.2 选择器2.3 CSS 常用属性2.3.1 字体属性2.3.2 文本属性2.3.3 背景属性2.4 圆角矩形2.5 元素的显示模式2.6 盒子模型2.7 弹性布局1. 前言 上文我们简单 将 HTML 过了一遍 &#xff0c; 知道了 HTML 知识表示页面的结构和内容 &#x…...

ChatGPT能完全取代软件开发吗,看看它怎么回答?

最近网上一直疯传&#xff0c;ChatGPT 最可能取代的 10 种工作。具体包括①、技术类工作&#xff1a;程序员、软件工程师、数据分析师②、媒体类工作&#xff1a;广告、内容创作、技术写作、新闻③、法律类工作&#xff1a;法律或律师助理④、市场研究分析师⑤、教师⑥、金融类…...

Vue3学习笔记

一、Ref ref, isRef, shallowRef, triggerRef, customRef ref返回的是es6的一个class类&#xff0c;取值和修改都要加上.valueref 和 shallowRef不能一起写&#xff0c;会引起shallowRef的视图更新ref shallowRef triggerRef <template><div class"home&quo…...

【React】pro-mobile

1.项目介绍 实现react移动端项目 2.目标&#xff1a; 能够应用CRAReactMobxAntd-mobile开发C端项目掌握基于React的C端项目开发流程学会如何应用next优化项目 3.使用技术栈 脚手架&#xff1a;cra dva-cliumi 脚本&#xff1a;ts react版本&#xff1a;react v18 2022年更…...

Substrate 基础教程(Tutorials) -- 授权特定节点

五、授权特定节点 在添加可信节点中&#xff0c;您看到了如何使用一组已知的验证器节点构建一个简单的网络。该教程演示了一个简化版的许可网络&#xff08;permissioned network&#xff09;。在一个被许可的网络中&#xff0c;只有被授权的节点&#xff08;authorized nodes…...

使用qemu-img转换镜像格式

qemu功能强大&#xff0c;详细了解其功能请到官网查看 https://www.qemu.org/docs/master/system/images.html qemu-img能将RAW、qcow2、VMDK、VDI、VHD&#xff08;vpc&#xff09;、VHDX、qcow1或QED格式的镜像转换成VHD格式&#xff0c;也可以实现RAW和VHD格式的互相转换。 …...

Springboot怎么集成Thymeleaf模板引擎?

Thymeleaf介绍Thymeleaf&#xff0c;是一个XML/XHTML/HTML模板引擎&#xff0c;开源的java库&#xff0c;可以用于SpingMVC项目中&#xff0c;用于代替JSP、FreeMarker或者其他的模板引擎&#xff1b;页面与数据分离&#xff0c;提高了开发效率&#xff0c;让代码重用更容易。S…...

LiveGBS国标GB/T28181视频流媒体平台-功能视频集中录制存储云端录像H264|H265|HEVC视频存储

LiveGBS国标GB/T28181视频流媒体平台-视频集中录制存储云端录像H264|H265|HEVC视频存储1、云端录像存储2、手动配置录像2.1、按需录像2.2、一直录像3、录像计划3.1、录像计划入口3.2、新增录像计划3.3、编辑录像计划3.4、关联通道4、查看云端录像4.1、查看录像4.1.1、时间轴模式…...

IntelliJ IDEA如何整合Maven图文教程详解

Maven 1.Maven简述 Maven是一个构建工具,服务与构建.使用Maven配置好项目后,输入简单的命令,如:mvn clean install,Maven会帮我们处理那些繁琐的任务. Maven是跨平台的. Maven最大化的消除了构建的重复. Maven可以帮助我们标准化构建过程.所有的项目都是简单一致的,简化了学习…...

图数据库认证考试 NGCP 错题解析 vol.02:这 10 道题竟无一人全部答对

如果你读过「NebulaGraph 错题解析第一期」&#xff0c;大概知道在错题解析未出来之前&#xff0c;NebulaGraph 专业技能认证 NGCP&#xff08;全称 NebulaGraph Certified Professional&#xff09;的通过率仅有 16.7%。但是&#xff0c;经过上一轮 NebulaGraph 认证考试出题人…...

188888

81. 一个敏捷项目正在进行八次迭代中的第五次迭代。在最后一次迭代计划之后&#xff0c;团队得知市场上出现一个新的竞争对手&#xff0c;有必要更快地加快进程来确保不失去市场份额。 项目经理应该怎么做&#xff1f; A 将竞争对手的功能添加到产品积压待办清单中&#xff0c;…...

华为机试题:HJ99 自守数(python)

文章目录&#xff08;1&#xff09;题目描述&#xff08;2&#xff09;Python3实现&#xff08;3&#xff09;知识点详解1、input()&#xff1a;获取控制台&#xff08;任意形式&#xff09;的输入。输出均为字符串类型。1.1、input() 与 list(input()) 的区别、及其相互转换方…...

如何提高推广邮件的发送成功率?

随着经济的发展&#xff0c;国际之间的贸易往来越加频繁&#xff0c;很多外贸企业需要发送大量的商业推广邮件&#xff0c;来获得销售订单开拓公司业务市场。 随之而来的问题也是越来越多&#xff0c;给众多的外贸企业带来诸多的困扰。外贸企业在发送推广邮件中究竟会遇到什么问…...

关于提高PX4抗风性

滚转角速率控制器&#xff1a;&#xff08;MC_ROLLRATE_P&#xff0c; MC_ROLLRATE_I&#xff0c; MC_ROLLRATE_D&#xff09; 滚转角速率控制器&#xff1a;&#xff08;MC_PITCHRATE_P&#xff0c; MC_PITCHRATE_I&#xff0c;MC_PITCHRATE_D&#xff09; 滚转角速率控制器…...

AVL 树实现

AVL 树的概念 也许因为插入的值不够随机&#xff0c;也许因为经过某些插入或删除操作&#xff0c;二叉搜索树可能会失去平衡&#xff0c;甚至可能退化为单链表&#xff0c;造成搜索效率低。 AVL Tree 是一个「加上了额外平衡条件」的二叉搜索树&#xff0c;其平衡条件的建立是…...

跟我学c++高级篇——模板元编程之八惰性加载

一、Lazy evaluation 惰性加载或者延迟计算&#xff0c;在前面的文章《跟我学c中级篇——迟延计算》中分析过。叫法怎么叫都可以&#xff0c;只要大家明白这个意思即可。Lazy evaluation一般可用于下面的情况&#xff1a; 1、模板中的对象非立刻的模板实例化&#xff0c;也就是…...

【Python入门第二十二天】Python 类和对象

Python 类/对象 Python 是一种面向对象的编程语言。 Python 中的几乎所有东西都是对象&#xff0c;拥有属性和方法。 类&#xff08;Class&#xff09;类似对象构造函数&#xff0c;或者是用于创建对象的“蓝图”。 创建类 如需创建类&#xff0c;请使用 class 关键字&…...

商城网站建设机构/广州seo排名优化

一、思路 购买书总共有十种方案&#xff0c;每一种方案单独考虑。因此只需要分情况考虑就行。 二、代码 //书店针对《哈利波特》系列书籍进行促销活动&#xff0c;一共5卷&#xff0c;用编号0、1、2、3、4表示&#xff0c;单独一卷售价8元&#xff0c; 具体折扣如下所示&#x…...

有中文网站 怎么做英文网站/百度推广话术全流程

1、项目的典型用户与场景 2、对其他组评价 强强联手队项目做得很好&#xff0c;不过如果能够把连网操作就更好了。 滑稽队项目的前台设计挺好&#xff0c;如果把包车的信息都放进数据库就更好了。 梦之翼队的项目做得不错&#xff0c;可以看出他们做得非常的认真&#xff0c;但…...

地坪漆东莞网站建设技术支持/辽宁网站建设

我们在有些开发时候可能会用到些头条的文章&#xff0c;&#xff0c;添加过程如下所示&#xff1a; 我们在前台遍历数据的时候可以这样&#xff0c; 然后在后台更新首页模版后在去看下首页&#xff0c;效果如下所示&#xff1a; 转载于:https://www.cnblogs.com/leigood/p/5301…...

量子秘密网站怎么做/网站分析培训班

&#xff08;注意&#xff01;非广告洗脑文&#xff0c;请注意甄别。&#xff09; 执行力不够怎么办&#xff1f; 今天想学习3个小时内容&#xff0c;可惜只坚持了30分钟。 今天想把某功能用例写完&#xff0c;可惜只写了一半。 今天想开发个自动化脚本&#xff0c;可惜开个…...

学校网站系统破解版/推广app用什么平台比较好

作者 | kbsc13来源 | 机器学习与计算机视觉&#xff08;ID&#xff1a;AI_Developer&#xff09;上周结束了如何构造一个机器学习项目的系列文章&#xff0c;当然还有一篇简单的总结以及介绍一些入门的学习资料&#xff0c;不过还在整理&#xff0c;应该这周内会整理好的。现在…...

网站做好后怎么做seo/免费制作网站app

#!/usr/bin/env python#! _*_ coding:utf-8 _*_ #注:多实例DB数据,my.conf,sock文件目录要统一#每个实例要建有shutdown权限mt_user用户 import os,sysimport socket myd /usr/local/mysql/bin/mysqld#1myadmin /usr/local/mysql/bin/mysqladminm_user rootm_password exsd…...