-
Notifications
You must be signed in to change notification settings - Fork 88
Expand file tree
/
Copy pathpeterbe.html
More file actions
367 lines (256 loc) · 15.6 KB
/
peterbe.html
File metadata and controls
367 lines (256 loc) · 15.6 KB
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<title>Time to do concurrent CPU bound work - Peterbe.com</title>
<link
href="//fonts.googleapis.com/css?family=Lato:400,700,400italic&subset=latin"
rel="stylesheet"
type="text/css"
data-mincss="ignore">
<link href="peterbe.css" rel="stylesheet" type="text/css" />
<link href="peterbe-nomincss.css" rel="stylesheet" type="text/css" data-mincss="no" />
<meta name="description" content="Stuff in Peter's head">
<link rel="shortcut icon" href="//cdn-2916.kxcdn.com/static/images/favicon-32.f33a02760a1e.png">
<link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml">
<meta name="keywords" content="deco,concurrent,concurrency,parallel,thumbnails">
<style>
span.not-approved { /* no mincss */
float:right;
font-size:90%;
color:red;
}
</style>
</head>
<body>
<div class="ui main text container">
<h1 class="ui header">Time to do concurrent CPU bound work</h1>
<p>
13 May 2016
<span class="comment-count">
3 comments
</span>
<a href="/oc-Python"
rel="nofollow"
title="Filter by the 'Python' category"
>Python</a>,
<a href="/oc-Linux"
rel="nofollow"
title="Filter by the 'Linux' category"
>Linux</a>,
<a href="/oc-MacOSX"
rel="nofollow"
title="Filter by the 'MacOSX' category"
>MacOSX</a>
</p>
<h4><a href="https://docs.google.com/spreadsheets/d/1uCjMXKygM_SAxBBv8Wm-dBjGIs5YQR5wlYzOPavfArc/edit?usp=sharing">https://docs.google.com/spreadsheets/d/1uCjMXKygM_SAxBBv8Wm-dBjGIs5YQR5wlYzOPavfArc/edit?usp=sharing</a></h4>
</div>
<div class="ui borderless main menu fixed" style="display:none"></div>
<div class="ui borderless main menu">
<div class="ui text container">
<div href="#" class="header item">
<a href="/"><img class="logo" src="//cdn-2916.kxcdn.com/static/images/favicon-32.f33a02760a1e.png"></a>
<a href="/">Peterbe.com</a>
<a class="page-title-repeated">Time to do concurrent CPU bound work</a>
</div>
<div class="right menu">
<a href="/plog/" class="ui item">Archive</a>
<a href="/about" class="ui item">About</a>
<a href="/contact" class="ui item">Contact</a>
<form action="/search" class="navbar-form navbar-right" role="search">
<div class="item ui input">
<input type="text" name="q"
maxlength="90"
placeholder="Search" >
</div>
</form>
</div>
<div href="#" class="ui right floated dropdown item">
Menu<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="/plog/">Archive</a>
<a class="item" href="/about">About</a>
<a class="item" href="/contact">Contact</a>
<a class="item" href="/search">Search</a>
</div>
</div>
</div>
</div>
<div class="ui text container">
<p>Did you see my blog post about <a href="/plog/deco">Decorated Concurrency - Python multiprocessing made really really easy</a>? If not, fear not. There, I'm demonstrating how I take a task of creating 100 thumbnails from a large JPG. First in serial, then concurrently, with a library called <a href="https://github.com/alex-sherman/deco">deco</a>. The total time to get through the work massively reduces when you do it concurrently. No surprise. But what's interesting is that each individual task takes a lot longer. Instead of <strong>0.29 seconds per image</strong> it took <strong>0.65 seconds per image</strong> (...inside each dedicated processor). </p>
<p>The simple explanation, even from a layman like myself, must be that when doing so much more, concurrently, the whole operating system struggles to keep up with other little subtle tasks. </p>
<p>With <code>deco</code> you can either let Python's <code>multiprocessing</code> just use as many CPUs as your computer has (8 in the case of my Macbook Pro) or you can manually set it. E.g. <code>@concurrent(processes=5)</code> would spread the work across a max of 5 CPUs. </p>
<p>So, I ran my little experiment again for every number from 1 to 8 and plotted the results: </p>
<p><img alt="Time elapsed vs. work time" src="//cdn-2916.kxcdn.com/cache/5a/83/5a835822ba4682edbb836818c056a1a9.png"> </p>
<h3>What to take away...</h3>
<p>The blue bars is the time it takes, in total, from starting the program till the program ends. The lower the better. </p>
<p>The red bars is the time it takes, in total, to complete each individual task. </p>
<p>Meaning, when the number of CPUs is <strong>low</strong> you have to wait longer for all the work to finish and when the number of CPUs is <strong>high</strong> the computer needs more time to finish its work. This is an insight into over-use of operating system resources. </p>
<p>If the work is much much more demanding than this experiment (the JPG is only 3.3Mb and one thumbnail only takes 0.3 seconds to make) you might have a red bar on the far right that is too expensive for your server. Or worse, it might break things so that everything stops. </p>
<h3>In conclusion...</h3>
<p>Choose wisely. Be aware how "bound" the task is. </p>
<p>Also, remember that if the work of each individual task is too "light", the overhead of messing with multprocessing might actually cost more than it's worth. </p>
<h3>The code</h3>
<p>Here's the messy code I used: </p>
<div class="highlight">
<pre><span></span><span class="kn">import</span> <span class="nn">time</span>
<span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span>
<span class="kn">from</span> <span class="nn">deco</span> <span class="kn">import</span> <span class="n">concurrent</span><span class="p">,</span> <span class="n">synchronized</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="n">processes</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="k">assert</span> <span class="n">processes</span> <span class="o">>=</span> <span class="mi">1</span>
<span class="k">assert</span> <span class="n">processes</span> <span class="o"><=</span> <span class="mi">8</span>
<span class="nd">@concurrent</span><span class="p">(</span><span class="n">processes</span><span class="o">=</span><span class="n">processes</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">slow</span><span class="p">(</span><span class="n">times</span><span class="p">,</span> <span class="n">offset</span><span class="p">):</span>
<span class="n">t0</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">path</span> <span class="o">=</span> <span class="s1">'9745e8.jpg'</span>
<span class="n">img</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
<span class="n">size</span> <span class="o">=</span> <span class="p">(</span><span class="mi">100</span> <span class="o">+</span> <span class="n">offset</span> <span class="o">*</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">100</span> <span class="o">+</span> <span class="n">offset</span> <span class="o">*</span> <span class="mi">20</span><span class="p">)</span>
<span class="n">img</span><span class="o">.</span><span class="n">thumbnail</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="n">Image</span><span class="o">.</span><span class="n">ANTIALIAS</span><span class="p">)</span>
<span class="n">img</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s1">'thumbnails/{}.jpg'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">offset</span><span class="p">),</span> <span class="s1">'JPEG'</span><span class="p">)</span>
<span class="n">t1</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">times</span><span class="p">[</span><span class="n">offset</span><span class="p">]</span> <span class="o">=</span> <span class="n">t1</span> <span class="o">-</span> <span class="n">t0</span>
<span class="nd">@synchronized</span>
<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="n">times</span><span class="p">):</span>
<span class="k">for</span> <span class="n">index</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">):</span>
<span class="n">slow</span><span class="p">(</span><span class="n">times</span><span class="p">,</span> <span class="n">index</span><span class="p">)</span>
<span class="n">t0</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
<span class="n">times</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">run</span><span class="p">(</span><span class="n">times</span><span class="p">)</span>
<span class="n">t1</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
<span class="k">print</span> <span class="s2">"TOOK"</span><span class="p">,</span> <span class="n">t1</span><span class="o">-</span><span class="n">t0</span>
<span class="k">print</span> <span class="s2">"WOULD HAVE TAKEN"</span><span class="p">,</span> <span class="nb">sum</span><span class="p">(</span><span class="n">times</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
</pre></div>
<h2>UPDATE</h2>
<p>I just wanted to verify that the experiment is valid that proves that CPU bound work hogs resources acorss CPUs that affects their individual performance. </p>
<p>Let's try to the similar but totally different workload of a <strong>Network bound</strong> task. This time, instead of resizing JPEGs, it waits for finishing HTTP GET requests. </p>
<p><img alt="Network bound" src="//cdn-2916.kxcdn.com/cache/79/b7/79b7270db10b38cea08bffb81053aaca.png"> </p>
<p>So clearly it makes sense. The individual work <strong>withing each process</strong> is not generally slowed down much. A tiny bit, but not much. Also, I like the smoothness of the curve of the blue bars going from left to right. You can clearly see that it's reverse logarithmic. </p>
<section id="buttons" style="display:none">
<a href="https://twitter.com/peterbe" class="twitter-follow-button" data-show-count="false">Follow @peterbe</a>
</section>
<h2 class="ui dividing header">Comments</h2>
<div id="comments-outer" class="ui comments">
<div id="c79dfe5" class="comment">
<div class="content">
<a class="author">Albert Mietus</a>
<div class="metadata">
<span class="date">14 May 2016</span>
<button data-oid="c79dfe5" name="delete">Delete</button>
</div>
<div class="text">
Using a dict -specialty passing it around- to do the timing bookkeeping can be costly. Possibly that has more effect on the graphs than expected. <br><br>Returning the time (as int) and storing it in run function- even in the dict- can speed. And give more objective results.
</div>
<div class="actions">
<a class="reply" rel="nofollow" data-oid="c79dfe5"
href="#c79dfe5">Reply</a>
</div>
</div>
<div class="comments">
</div>
</div>
<div id="ce9502b" class="comment">
<div class="content">
<a class="author">Jorgen</a>
<div class="metadata">
<span class="date">16 May 2016</span>
<button data-oid="ce9502b" name="delete">Delete</button>
</div>
<div class="text">
Does your MacBook have 4 cores with hyperthreading? If so that explains why the effect peters out at 4 processes. If the task is CPU-bound then hyperthreading generally does not offer a big performance boost.
</div>
<div class="actions">
<a class="reply" rel="nofollow" data-oid="ce9502b"
href="#ce9502b">Reply</a>
</div>
</div>
<div class="comments">
<div id="c7e5bd5" class="comment">
<div class="content">
<a class="author">Peter Bengtsson</a>
<div class="metadata">
<span class="date">20 May 2016</span>
<button data-oid="c7e5bd5" name="delete">Delete</button>
</div>
<div class="text">
I don't know. It's just a standard Macbook Pro.
</div>
<div class="actions">
<a class="reply" rel="nofollow" data-oid="c7e5bd5"
href="#c7e5bd5">Reply</a>
</div>
</div>
<div class="comments">
</div>
</div>
</div>
</div>
</div>
<div id="preview-comment-outer" class="ui comments preview" style="display:none"></div>
<form action="/plog/time-to-do-concurrent-cpu-bound-work/submit" method="post" id="comment" class="ui form">
<div class="ui inverted dimmer">
<div class="ui text loader">Thank you for posting a comment</div>
</div>
<div class="field">
<label>What do you think?</label>
<textarea name="comment" tabindex="1" rows="5"></textarea>
</div>
<div class="field">
<input type="hidden" name="csrfmiddlewaretoken" value="">
<input type="hidden" name="parent" value="">
<div class="two fields">
<div class="field">
<input name="name" placeholder="Your full name" title="Your full name" tabindex="2">
</div>
<div class="field">
<input name="email" placeholder="Your email" title="Your email" tabindex="3">
</div>
</div>
<p class="note">Your email will never ever be published</p>
</div>
<button type="submit" class="ui button primary preview" tabindex="4">Preview first</button>
<button type="submit" class="ui button post" tabindex="5">Post comment</button><br>
<p class="cancel" style="display:none"><a href="./" title="Abandon ship!">Cancel</a></p>
</form>
<h2 class="ui dividing header">Related posts</h2>
<dl>
<dt>Previous:</dt>
<dd><a href="/plog/deco">Decorated Concurrency - Python multiprocessing made really really easy</a>
<small>13 May 2016</small>
</dd>
<dt>Next:</dt>
<dd><a href="/plog/hashin-0.5.0-bug-fix">hashin 0.5.0 bug fix</a>
<small>17 May 2016</small>
</dd>
</dl>
<dl>
<dt>Related by keywords:</dt>
<dd><a href="/plog/deco" data-plogrank="17214.0">Decorated Concurrency - Python multiprocessing made really really easy</a>
<small>13 May 2016</small>
</dd>
</dl>
</div>
<div class="ui inverted vertical footer segment">
<div class="ui center aligned container">
<div class="ui horizontal inverted small divided link list">
<p>
© peterbe.com 2003 - 2016
⋅
Hosted on <a href="https://www.digitalocean.com/?refcode=9c9126b69f33"
title="Yes, following this link and signing up will give me a small referal bonus :)"
>Digital Ocean</a>
</p>
<a class="item" href="/">Home</a>
<a class="item" href="/plog/">Archive</a>
<a class="item" href="/about">About</a>
<a class="item" href="/contact">Contact</a>
<a class="item" href="/search">Search</a>
</div>
</div>
</div>
</body>
</html>