Skip to content

Commit 57aa590

Browse files
committed
Lab10: Added task switching exercise.
1 parent ffcb550 commit 57aa590

File tree

1 file changed

+87
-1
lines changed

1 file changed

+87
-1
lines changed

docs/src/lecture_10/lab.md

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,94 @@ df[1:50,:]
253253
### Multithreaded file processing
254254

255255
## Task switching
256+
There is a way how to run "multiple" things at once, which does not necessarily involve either threads or processes. In Julia this concept is called task switching or asynchronous programming, where we fire off our requests in a short time and let the cpu/os/network handle the distribution. As an example which we will try today is querrying a web API, which has some variable latency. In the usuall sequantial fashion we can always post querries one at a time, however generally the APIs can handle multiple request at a time, therefore in order to better utilize them, we can call them asynchronously and fetch all results later, in some cases this will be faster.
256257

257-
### Only if we I come up with something interesting
258+
!!! info "Burst requests"
259+
It is a good practice to check if an API supports some sort of batch request, because making a burst of single request might lead to a worse performance for others and a possible blocking of your IP/API key.
260+
261+
Consider following functions
262+
```julia
263+
function a()
264+
for i in 1:10
265+
sleep(1)
266+
end
267+
end
268+
269+
function b()
270+
for i in 1:10
271+
@async sleep(1)
272+
end
273+
end
274+
275+
function c()
276+
@sync for i in 1:10
277+
@async sleep(1)
278+
end
279+
end
280+
```
281+
282+
```@raw html
283+
</div></div>
284+
<details class = "solution-body">
285+
<summary class = "solution-header">How much time will take the execution of each of them?:</summary><p>
286+
```
287+
```
288+
```julia
289+
@time a() # 10s
290+
@time b() # ~0s
291+
@time c() # >~1s
292+
```
293+
```@raw html
294+
</p></details>
295+
```
296+
297+
```@raw html
298+
<div class="admonition is-category-exercise">
299+
<header class="admonition-header">Exercise</header>
300+
<div class="admonition-body">
301+
```
302+
Choose one of the free web APIs and query its endpoint using the `HTTP.jl` library. Implement both sequential and asynchronous version. Compare them on an burst of 10 requests.
303+
304+
**HINTS**:
305+
- use `HTTP.request` for `GET` requests on your chosen API, e.g. `r = HTTP.request("GET", "https://catfact.ninja/fact")` for random cat fact
306+
- converting body of a response can be done simply by constructing a `String` out of it - `String(r.body)`
307+
- in order to parse a json string use `JSON.jl`'s parse function
308+
- Julia offers `asyncmap` - asynchronous `map`
309+
310+
```@raw html
311+
</div></div>
312+
<details class = "solution-body">
313+
<summary class = "solution-header">Solution:</summary><p>
314+
```
315+
316+
```julia
317+
using HTTP, JSON
318+
319+
function query_cat_fact()
320+
r = HTTP.request("GET", "https://catfact.ninja/fact")
321+
j = String(r.body)
322+
d = JSON.parse(j)
323+
d["fact"]
324+
end
325+
326+
function get_cat_facts_async(n)
327+
facts = String[]
328+
@sync for i in 1:10
329+
@async facts query_cat_fact()
330+
end
331+
facts
332+
end
333+
334+
get_cat_facts_async(n) = asyncmap(x -> query_cat_fact(), Base.OneTo(n))
335+
get_cat_facts(n) = map(x -> query_cat_fact(), Base.OneTo(n))
336+
337+
@time get_cat_facts_async(10) # ~0.15s
338+
@time get_cat_facts(10) # ~1.1s
339+
```
340+
341+
```@raw html
342+
</p></details>
343+
```
258344

259345

260346
## Summary

0 commit comments

Comments
 (0)