Skip to content

Commit fbda12d

Browse files
committed
initial version
1 parent 2205fc4 commit fbda12d

File tree

7 files changed

+317
-1
lines changed

7 files changed

+317
-1
lines changed

README.md

+45-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,46 @@
11
# python-concurrency
2-
Concurrency in Python
2+
Concurrency and parallelism in Python
3+
4+
Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once.
5+
-- Rob Pike, co-inventor da linguagem Go - Concurrency is not Parallelism (it's better)
6+
7+
- Ao preparar vários pratos ao mesmo tempo o cozinheiro está trabalhando de forma concorrente, porque normalmente ele só cuida de um prato por vez, mas vários estão sendo preparados ao mesmo tempo.
8+
9+
- Por outro lado, um fogão de 6 bocas permite aquecer 6 panelas em paralelo.
10+
11+
- Ou seja, o cozinheiro trabalha em modo concorrente e o fogão em modo paralelo.
12+
-- [Garoa Hacker Clube](https://garoa.net.br/wiki/Python_Concorrente)
13+
14+
# Install packages
15+
16+
* requests
17+
* asyncio
18+
* aiohttp
19+
20+
21+
# Benchmarks
22+
23+
Benchmark name | (1) | (2) | (3) | (4)
24+
-------------------------------------|-----------:|-----------:|-----------:|-----------:
25+
synchronous (sync.py) | 17.366073 | 17.226306 | 15.457684 | 15.195825
26+
thread with 5 workers (thread.py) | 3.248359 | 2.758202 | 1.843235 | 1.813232
27+
thread with 50 workers (thread.py) | 0.625699 | 0.756632 | 0.573231 | 0.587740
28+
parallelism (multiprocess.py) | 3.607703 | 3.317795 | 2.845974 | 2.705426
29+
asynchronous coroutines (async.py) | 0.586605 | 0.609510 | 0.571612 | 0.579693
30+
31+
* Time in seconds
32+
* (1) with Python 3.6.5
33+
* (2) with Python 3.6.5
34+
* (3) with Python 3.8.0
35+
* (4) with Python 3.8.0
36+
37+
# References
38+
39+
* [en] [Coroutines and Tasks - Official Python Docs](https://docs.python.org/3/library/asyncio-task.html)
40+
* [en] [threading — Thread-based parallelism - Official Python Docs](https://docs.python.org/3/library/threading.html)
41+
* [en] [multiprocessing — Process-based parallelism - Official Python Docs](https://docs.python.org/3/library/multiprocessing.html)
42+
* [en] [Speed Up Your Python Program With Concurrency](https://realpython.com/python-concurrency)
43+
* [en] [An Intro to Threading in Python](https://realpython.com/intro-to-python-threading)
44+
* [en] [Async IO in Python: A Complete Walkthrough](https://realpython.com/async-io-python)
45+
* [en] [AsyncIO for the Working Python Developer - Yeray Diaz](https://hackernoon.com/asyncio-for-the-working-python-developer-5c468e6e2e8e)
46+
* [pt-br] [AsyncIO - O futuro do Python mudou completamente! - Bruno Rocha](http://brunorocha.org/python/asyncio-o-futuro-do-python-mudou-completamente.html)

async.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import asyncio
2+
import json
3+
from time import time
4+
from aiohttp import ClientSession
5+
from config import api_key, url_base
6+
7+
8+
async def how_is_the_weather(client, city):
9+
api_url = (f"{url_base}/weather?q={city}&units=metric&APPID={api_key}")
10+
11+
async with client.get(api_url) as r:
12+
weather = await r.json()
13+
return weather.get("main", {}).get("temp", "0.0")
14+
15+
16+
async def main(loop):
17+
requests = []
18+
cities = []
19+
with open('cities.json', encoding='utf-8') as cities_json:
20+
cities_load = json.load(cities_json)
21+
[cities.append(c["name"]) for c in cities_load]
22+
23+
async with ClientSession() as session:
24+
for city in cities:
25+
requests.append(how_is_the_weather(session, city))
26+
temps = await asyncio.gather(*requests)
27+
28+
for city, temp in zip(cities, temps):
29+
print(f"Current weather in {city} is {temp} ºC")
30+
31+
32+
if __name__ == "__main__":
33+
loop = asyncio.get_event_loop()
34+
initial_time = time()
35+
loop.run_until_complete(main(loop))
36+
elapsed_time = time() - initial_time
37+
print(f"Total Time: {elapsed_time}")

cities.json

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
[
2+
{
3+
"id": 1,
4+
"name": "Cuiabá"
5+
},
6+
{
7+
"id": 2,
8+
"name": "São Paulo"
9+
},
10+
{
11+
"id": 3,
12+
"name": "Rio de Janeiro"
13+
},
14+
{
15+
"id": 4,
16+
"name": "Brasília"
17+
},
18+
{
19+
"id": 5,
20+
"name": "Buenos Aires"
21+
},
22+
{
23+
"id": 6,
24+
"name": "Santiago"
25+
},
26+
{
27+
"id": 7,
28+
"name": "Fairbanks"
29+
},
30+
{
31+
"id": 8,
32+
"name": "Lima"
33+
},
34+
{
35+
"id": 9,
36+
"name": "La Paz"
37+
},
38+
{
39+
"id": 10,
40+
"name": "Dubai"
41+
},
42+
{
43+
"id": 11,
44+
"name": "Quito"
45+
},
46+
{
47+
"id": 12,
48+
"name": "Caracas"
49+
},
50+
{
51+
"id": 13,
52+
"name": "Bogotá"
53+
},
54+
{
55+
"id": 14,
56+
"name": "Rondonópolis"
57+
},
58+
{
59+
"id": 15,
60+
"name": "New York"
61+
},
62+
{
63+
"id": 16,
64+
"name": "Miami"
65+
},
66+
{
67+
"id": 17,
68+
"name": "Chicago"
69+
},
70+
{
71+
"id": 18,
72+
"name": "Los Angeles"
73+
},
74+
{
75+
"id": 19,
76+
"name": "San Diego"
77+
},
78+
{
79+
"id": 20,
80+
"name": "Las Vegas"
81+
},
82+
{
83+
"id": 21,
84+
"name": "Toronto"
85+
},
86+
{
87+
"id": 22,
88+
"name": "Montreal"
89+
},
90+
{
91+
"id": 23,
92+
"name": "Vancouver"
93+
},
94+
{
95+
"id": 24,
96+
"name": "Halifax"
97+
},
98+
{
99+
"id": 25,
100+
"name": "London"
101+
},
102+
{
103+
"id": 26,
104+
"name": "Paris"
105+
},
106+
{
107+
"id": 27,
108+
"name": "Campo Grande"
109+
},
110+
{
111+
"id": 28,
112+
"name": "Curitiba"
113+
},
114+
{
115+
"id": 29,
116+
"name": "Florianópolis"
117+
},
118+
{
119+
"id": 30,
120+
"name": "Porto Alegre"
121+
}
122+
]

config.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
api_key = "c25ad98fd82f683d09832deb416a71f7"
2+
url_base = "http://api.openweathermap.org/data/2.5"
3+
thread_max_workers = 50

multiprocess.py

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import concurrent.futures
2+
import requests
3+
import multiprocessing
4+
import json
5+
from time import time
6+
from config import api_key, url_base
7+
8+
9+
session = None
10+
11+
def set_global_session():
12+
global session
13+
if not session:
14+
session = requests.Session()
15+
16+
17+
def how_is_the_weather(city):
18+
api_url = (f"{url_base}/weather?q={city}&units=metric&APPID={api_key}")
19+
20+
with session.get(api_url) as response:
21+
weather = response.json()
22+
temp = weather.get("main", {}).get("temp", "0.0")
23+
print(f"Current weather in {city} is {temp} ºC")
24+
25+
def weather_cities(cities):
26+
with multiprocessing.Pool(initializer=set_global_session) as pool:
27+
pool.map(how_is_the_weather, cities)
28+
29+
30+
if __name__ == "__main__":
31+
32+
cities = []
33+
with open('cities.json', encoding='utf-8') as cities_json:
34+
cities_load = json.load(cities_json)
35+
[cities.append(c["name"]) for c in cities_load]
36+
37+
initial_time = time()
38+
weather_cities(cities)
39+
elapsed_time = time() - initial_time
40+
print(f"Total time: {elapsed_time}")

sync.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from time import time
2+
import requests
3+
import json
4+
from config import api_key, url_base
5+
6+
7+
def how_is_the_weather(city):
8+
api_url = (f"{url_base}/weather?q={city}&units=metric&APPID={api_key}")
9+
10+
response = requests.get(api_url)
11+
weather = response.json()
12+
return weather.get("main", {}).get("temp", "0.0")
13+
14+
15+
if __name__ == "__main__":
16+
initial_time = time()
17+
18+
cities = []
19+
with open('cities.json', encoding='utf-8') as cities_json:
20+
cities_load = json.load(cities_json)
21+
[cities.append(c["name"]) for c in cities_load]
22+
23+
for city in cities:
24+
temp = how_is_the_weather(city)
25+
print(f"Current weather in {city} is {temp} ºC")
26+
27+
elapsed_time = time() - initial_time
28+
print(f"Total time: {elapsed_time}")

thread.py

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import concurrent.futures
2+
import requests
3+
import threading
4+
import json
5+
from time import time
6+
from config import api_key, url_base, thread_max_workers
7+
8+
9+
thread_local = threading.local()
10+
11+
def get_session():
12+
if not hasattr(thread_local, "session"):
13+
thread_local.session = requests.Session()
14+
return thread_local.session
15+
16+
17+
def how_is_the_weather(city):
18+
session = get_session()
19+
api_url = (f"{url_base}/weather?q={city}&units=metric&APPID={api_key}")
20+
21+
with session.get(api_url) as response:
22+
weather = response.json()
23+
temp = weather.get("main", {}).get("temp", "0.0")
24+
print(f"Current weather in {city} is {temp} ºC")
25+
26+
27+
def weather_cities(cities):
28+
with concurrent.futures.ThreadPoolExecutor(max_workers=thread_max_workers) as executor:
29+
executor.map(how_is_the_weather, cities)
30+
31+
32+
if __name__ == "__main__":
33+
initial_time = time()
34+
35+
cities = []
36+
with open('cities.json', encoding='utf-8') as cities_json:
37+
cities_load = json.load(cities_json)
38+
[cities.append(c["name"]) for c in cities_load]
39+
40+
weather_cities(cities)
41+
elapsed_time = time() - initial_time
42+
print(f"Total time: {elapsed_time}")

0 commit comments

Comments
 (0)