Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Dec 2, 2021. It is now read-only.

Commitdd16448

Browse files
committed
updated more ch. 17 examples to Python 3.7
1 parent176dc38 commitdd16448

9 files changed

+594
-0
lines changed

‎17-futures-py3.7/countries/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
flags/

‎17-futures-py3.7/countries/README.rst

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
============================
2+
Setting up Nginx and Vaurien
3+
============================
4+
5+
This text explains how to configure Nginx and Vaurien to test HTTP client code while avoiding network traffic and introducing simulated delays and errors. This setup is necessary if you want to experiment with the ``flags2*.py`` image download examples in this directory -- covered in chapters 17 and 18 of Fluent Python.
6+
7+
8+
Overview
9+
========
10+
11+
The flag download examples are designed to compare the performance of different approaches to finding and downloading files from the Web. However, we don't want to hit a public server with multiple requests per second while testing, and we want to be able to simulate high latency and random network errors.
12+
13+
For this setup I chose Nginx as the HTTP server because it is very fast and easy to configure, and Toxiproxy — designed by Shopify to introduce delays and network errors for testing distributed systems.
14+
15+
The archive ``flags.zip``, contains a directory ``flags/`` with 194 subdirectories, each containing a ``.gif`` image and a ``metadata.json`` file. These are public-domain images copied from the `CIA World Fact Book<https://www.cia.gov/library/publications/the-world-factbook/>`_.
16+
17+
Once these files are unpacked to the ``flags/`` directory and Nginx is configured, you can experiment with the ``flags2*.py`` examples without hitting the network.
18+
19+
20+
Procedure
21+
=========
22+
23+
1. Unpack test data
24+
-------------------
25+
26+
The instructions in this section are for GNU/Linux or OSX using the command line. Windows users should have no difficulty doing the same operations with the Windows Exporer GUI.
27+
28+
Unpack the initial data in the ``fancy_flags/`` directory::
29+
30+
$ unzip flags.zip
31+
... many lines omitted ...
32+
creating: flags/zw/
33+
inflating: flags/zw/metadata.json
34+
inflating: flags/zw/zw.gif
35+
36+
37+
Verify that 194 directories are created in ``fancy_flags/flags/``, each with a ``.gif`` and a ``metadata.json`` file::
38+
39+
40+
$ ls flags | wc -w
41+
194
42+
$ find flags | grep .gif | wc -l
43+
194
44+
$ find flags | grep .json | wc -l
45+
194
46+
$ ls flags/ad
47+
ad.gif metadata.json
48+
49+
50+
2. Install Nginx
51+
----------------
52+
53+
Download and install Nginx. I used version 1.6.2 -- the latest stable version as I write this.
54+
55+
* Download page: http://nginx.org/en/download.html
56+
57+
* Beginner's guide: http://nginx.org/en/docs/beginners_guide.html
58+
59+
60+
3. Configure Nginx
61+
------------------
62+
63+
Edit the the ``nginx.conf`` file to set the port and document root. You can determine which ``nginx.conf`` is in use by running::
64+
65+
66+
$ nginx -V
67+
68+
69+
The output starts with::
70+
71+
nginx version: nginx/1.6.2
72+
built by clang 6.0 (clang-600.0.51) (based on LLVM 3.5svn)
73+
TLS SNI support enabled
74+
configure arguments:...
75+
76+
77+
Among the configure arguments you'll see ``--conf-path=``. That's the file you will edit.
78+
79+
Most of the content in ``nginx.conf`` is within a block labeled ``http`` and enclosed in curly braces. Within that block there can be multiple blocks labeled ``server``. Add another ``server`` block like this one::
80+
81+
82+
server {
83+
listen 8001;
84+
85+
location /flags/ {
86+
root /full-path-to.../countries/;
87+
}
88+
}
89+
90+
91+
After editing ``nginx.conf`` the server must be started (if it's not running) or told to reload the configuration file::
92+
93+
94+
$ nginx # to start, if necessary
95+
$ nginx -s reload # to reload the configuration
96+
97+
98+
To test the configuration, open the URL http://localhost:8001/flags/ad/ad.gif in a browser. You should see the blue, yellow and red flag of Andorra.
99+
100+
If the test fails, please double check the procedure just described and refer to the Nginx documentation.
101+
102+
At this point you may run the ``flags_*2.py`` examples against the Nginx install by providing the ``--server LOCAL`` command line option. For example::
103+
104+
105+
$ python3 flags2_threadpool.py -s LOCAL
106+
LOCAL site: http://localhost:8001/flags
107+
Searching for 20 flags: from BD to VN
108+
20 concurrent connections will be used.
109+
--------------------
110+
20 flags downloaded.
111+
Elapsed time: 0.09s
112+
113+
114+
Note that Nginx is so fast that you will not see much difference in run time between the sequential and the concurrent versions. For more realistic testing with simulated network lag, we need to set up Toxiproxy.
115+
116+
117+
4. Install and run Toxiproxy
118+
----------------------------
119+
120+
Install...
121+
122+
In one terminal:
123+
124+
$ toxiproxy-server
125+
126+
In another terminal:
127+
128+
$ toxiproxy-cli create nginx_flags_delay -l localhost:8002 -u localhost:8001
129+
Created new proxy nginx_flags_delay
130+
$ toxiproxy-cli toxic add nginx_flags_delay -t latency -a latency=500
131+
Added downstream latency toxic 'latency_downstream' on proxy 'nginx_flags_delay'
132+
133+
134+
This creates an HTTP proxy on port 8002 which adds a 0.5s delay to every response. You can test it with a browser on port 8002: http://localhost:8002/flags/ad/ad.gif -- the flag of Andorra should appear after ½ second.
135+
136+
TODO: UPDATE NEXT PARAGRAPH
137+
138+
There is also the ``XXX`` script which runs a proxy on port 8003 producing errors in 25% of the responses and a .5 s delay to 50% of the responses. You can also test it with the browser on port 8003, but rememeber that errors are expected.
139+
140+
141+
Platform-specific instructions
142+
==============================
143+
144+
145+
Nginx setup on Mac OS X
146+
------------------------
147+
148+
Homebrew (copy & paste code at the bottom of http://brew.sh/)::
149+
150+
151+
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
152+
$ brew doctor
153+
$ brew install nginx
154+
155+
156+
Download and unpack::
157+
158+
Docroot is: /usr/local/var/www
159+
/usr/local/etc/nginx/nginx.conf
160+
161+
162+
::
163+
164+
To have launchd start nginx at login:
165+
ln -sfv /usr/local/opt/nginx/*.plist ~/Library/LaunchAgents
166+
Then to load nginx now:
167+
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.nginx.plist
168+
Or, if you don't want/need launchctl, you can just run:
169+
nginx
170+
171+
172+
173+
Nginx setup on Lubuntu 14.04.1 LTS
174+
----------------------------------
175+
176+
Docroot is: /usr/share/nginx/html
177+
178+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
AD AE AF AG AL AM AO AR AT AU AZ BA BB BD BE BF BG BH BI BJ BN BO BR BS BT
2+
BW BY BZ CA CD CF CG CH CI CL CM CN CO CR CU CV CY CZ DE DJ DK DM DZ EC EE
3+
EG ER ES ET FI FJ FM FR GA GB GD GE GH GM GN GQ GR GT GW GY HN HR HT HU ID
4+
IE IL IN IQ IR IS IT JM JO JP KE KG KH KI KM KN KP KR KW KZ LA LB LC LI LK
5+
LR LS LT LU LV LY MA MC MD ME MG MH MK ML MM MN MR MT MU MV MW MX MY MZ NA
6+
NE NG NI NL NO NP NR NZ OM PA PE PG PH PK PL PT PW PY QA RO RS RU RW SA SB
7+
SC SD SE SG SI SK SL SM SN SO SR SS ST SV SY SZ TD TG TH TJ TL TM TN TO TR
8+
TT TV TW TZ UA UG US UY UZ VA VC VE VN VU WS YE ZA ZM ZW
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
"""Download flags of countries (with error handling).
2+
3+
asyncio async/await version
4+
5+
"""
6+
# BEGIN FLAGS2_ASYNCIO_TOP
7+
importasyncio
8+
importcollections
9+
10+
importaiohttp
11+
fromaiohttpimportweb
12+
importtqdm
13+
14+
fromflags2_commonimportmain,HTTPStatus,Result,save_flag
15+
16+
# default set low to avoid errors from remote site, such as
17+
# 503 - Service Temporarily Unavailable
18+
DEFAULT_CONCUR_REQ=5
19+
MAX_CONCUR_REQ=1000
20+
21+
22+
classFetchError(Exception):# <1>
23+
def__init__(self,country_code):
24+
self.country_code=country_code
25+
26+
27+
asyncdefget_flag(session,base_url,cc):# <2>
28+
url='{}/{cc}/{cc}.gif'.format(base_url,cc=cc.lower())
29+
asyncwithsession.get(url)asresp:
30+
ifresp.status==200:
31+
returnawaitresp.read()
32+
elifresp.status==404:
33+
raiseweb.HTTPNotFound()
34+
else:
35+
raiseaiohttp.HttpProcessingError(
36+
code=resp.status,message=resp.reason,
37+
headers=resp.headers)
38+
39+
40+
asyncdefdownload_one(session,cc,base_url,semaphore,verbose):# <3>
41+
try:
42+
asyncwithsemaphore:# <4>
43+
image=awaitget_flag(session,base_url,cc)# <5>
44+
exceptweb.HTTPNotFound:# <6>
45+
status=HTTPStatus.not_found
46+
msg='not found'
47+
exceptExceptionasexc:
48+
raiseFetchError(cc)fromexc# <7>
49+
else:
50+
save_flag(image,cc.lower()+'.gif')# <8>
51+
status=HTTPStatus.ok
52+
msg='OK'
53+
54+
ifverboseandmsg:
55+
print(cc,msg)
56+
57+
returnResult(status,cc)
58+
# END FLAGS2_ASYNCIO_TOP
59+
60+
# BEGIN FLAGS2_ASYNCIO_DOWNLOAD_MANY
61+
asyncdefdownloader_coro(cc_list,base_url,verbose,concur_req):# <1>
62+
counter=collections.Counter()
63+
semaphore=asyncio.Semaphore(concur_req)# <2>
64+
asyncwithaiohttp.ClientSession()assession:# <8>
65+
to_do= [download_one(session,cc,base_url,semaphore,verbose)
66+
forccinsorted(cc_list)]# <3>
67+
68+
to_do_iter=asyncio.as_completed(to_do)# <4>
69+
ifnotverbose:
70+
to_do_iter=tqdm.tqdm(to_do_iter,total=len(cc_list))# <5>
71+
forfutureinto_do_iter:# <6>
72+
try:
73+
res=awaitfuture# <7>
74+
exceptFetchErrorasexc:# <8>
75+
country_code=exc.country_code# <9>
76+
try:
77+
error_msg=exc.__cause__.args[0]# <10>
78+
exceptIndexError:
79+
error_msg=exc.__cause__.__class__.__name__# <11>
80+
ifverboseanderror_msg:
81+
msg='*** Error for {}: {}'
82+
print(msg.format(country_code,error_msg))
83+
status=HTTPStatus.error
84+
else:
85+
status=res.status
86+
87+
counter[status]+=1# <12>
88+
89+
returncounter# <13>
90+
91+
92+
defdownload_many(cc_list,base_url,verbose,concur_req):
93+
loop=asyncio.get_event_loop()
94+
coro=downloader_coro(cc_list,base_url,verbose,concur_req)
95+
counts=loop.run_until_complete(coro)# <14>
96+
loop.close()# <15>
97+
98+
returncounts
99+
100+
101+
if__name__=='__main__':
102+
main(download_many,DEFAULT_CONCUR_REQ,MAX_CONCUR_REQ)
103+
# END FLAGS2_ASYNCIO_DOWNLOAD_MANY

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp