-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
560 lines (354 loc) · 222 KB
/
atom.xml
File metadata and controls
560 lines (354 loc) · 222 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
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Quentin's Blog</title>
<link href="/atom.xml" rel="self"/>
<link href="http://kunxiang.wang/"/>
<updated>2020-04-12T08:41:09.942Z</updated>
<id>http://kunxiang.wang/</id>
<author>
<name>ByiProX</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Java中的volatile关键字</title>
<link href="http://kunxiang.wang/2020/04/12/Java%E4%B8%AD%E7%9A%84volatile%E5%85%B3%E9%94%AE%E5%AD%97/"/>
<id>http://kunxiang.wang/2020/04/12/Java中的volatile关键字/</id>
<published>2020-04-12T08:40:41.000Z</published>
<updated>2020-04-12T08:41:09.942Z</updated>
<content type="html"><![CDATA[<p>Volatile [ˈvɑːlətl],中文解释:反复无常的,易变的,不稳定的。<br>volatile的本意是告诉编译器,此变量的值是易变的,每次读写该变量的值时务必从该变量的内存地址中读取或写入,不能为了效率使用对一个“临时”变量的读写来代替对该变量的直接读写。编译器看到了volatile关键字,就一定会生成内存访问指令,每次读写该变量就一定会执行内存访问指令直接读写该变量。若是没有volatile关键字,编译器为了效率,只会在循环开始前使用读内存指令将该变量读到寄存器中,之后在循环内都是用寄存器访问指令来操作这个“临时”变量,在循环结束后再使用内存写指令将这个寄存器中的“临时”变量写回内存。在这个过程中,如果内存中的这个变量被别的因素(其他线程、中断函数、信号处理函数、DMA控制器、其他硬件设备)所改变了,就产生数据不一致的问题。</p><p>volatile关键字在用C语言编写嵌入式软件里面用得很多,不使用volatile关键字的代码比使用volatile关键字的代码效率要高一些,但就无法保证数据的一致性。<br>在Java中,volatile 会确保我们对于这个变量的读取和写入,都一定会同步到主内存里,而不是从 Cache 里面读取。<br><a id="more"></a></p><h4 id="Case-1"><a href="#Case-1" class="headerlink" title="Case 1"></a>Case 1</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">VolatileTest</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">volatile</span> <span class="keyword">int</span> COUNTER = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">new</span> ChangeListener().start();</span><br><span class="line"> <span class="keyword">new</span> ChangeMaker().start();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">ChangeListener</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> threadValue = COUNTER;</span><br><span class="line"> <span class="keyword">while</span> ( threadValue < <span class="number">5</span>){</span><br><span class="line"> <span class="keyword">if</span>( threadValue!= COUNTER){</span><br><span class="line"> System.out.println(<span class="string">"Got Change for COUNTER : "</span> + COUNTER + <span class="string">""</span>);</span><br><span class="line"> threadValue= COUNTER;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">ChangeMaker</span> <span class="keyword">extends</span> <span class="title">Thread</span></span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> threadValue = COUNTER;</span><br><span class="line"> <span class="keyword">while</span> (COUNTER <<span class="number">5</span>){</span><br><span class="line"> System.out.println(<span class="string">"Incrementing COUNTER to : "</span> + (threadValue+<span class="number">1</span>) + <span class="string">""</span>);</span><br><span class="line"> COUNTER = ++threadValue;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread.sleep(<span class="number">500</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) { e.printStackTrace(); }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在这个程序里,我们先定义了一个 volatile 的 int 类型的变量,COUNTER。然后,我们分别启动了两个单独的线程,一个线程我们叫 ChangeListener。</p><p>ChangeListener 这个线程运行的任务很简单。它先取到 COUNTER 当前的值,然后一直监听着这个 COUNTER 的值。一旦 COUNTER 的值发生了变化,就把新的值通过 println 打印出来。直到 COUNTER 的值达到 5 为止。这个监听的过程,通过一个永不停歇的 while 循环的<code>忙等待</code>来实现。</p><p>另外一个 ChangeMaker 线程运行的任务同样很简单。它同样是取到 COUNTER 的值,在 COUNTER 小于 5 的时候,每隔 500 毫秒,就让 COUNTER 自增 1。在自增之前,通过 println 方法把自增后的值打印出来。</p><p>最后,在 main 函数里,我们分别启动这两个线程,来看一看这个程序的执行情况。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Incrementing COUNTER to : <span class="number">1</span></span><br><span class="line">Got Change <span class="keyword">for</span> COUNTER : <span class="number">1</span></span><br><span class="line">Incrementing COUNTER to : <span class="number">2</span></span><br><span class="line">Got Change <span class="keyword">for</span> COUNTER : <span class="number">2</span></span><br><span class="line">Incrementing COUNTER to : <span class="number">3</span></span><br><span class="line">Got Change <span class="keyword">for</span> COUNTER : <span class="number">3</span></span><br><span class="line">Incrementing COUNTER to : <span class="number">4</span></span><br><span class="line">Got Change <span class="keyword">for</span> COUNTER : <span class="number">4</span></span><br><span class="line">Incrementing COUNTER to : <span class="number">5</span></span><br><span class="line">Got Change <span class="keyword">for</span> COUNTER : <span class="number">5</span></span><br></pre></td></tr></table></figure><p>程序的输出结果并不让人意外。ChangeMaker 函数会一次一次将 COUNTER 从 0 增加到 5。因为这个自增是每 500 毫秒一次,而 ChangeListener 去监听 COUNTER 是<code>忙等待</code>的,所以每一次自增都会被 ChangeListener 监听到,然后对应的结果就会被打印出来。</p><p>终极原因是:volatile保证所有数据的读和写都来自<code>主内存</code>。ChangeMaker 和 ChangeListener 之间,获取到的 COUNTER 值就是一样的。</p><h4 id="Case-2"><a href="#Case-2" class="headerlink" title="Case 2"></a>Case 2</h4><p>如果我们把上面的程序小小地修改一行代码,把我们定义 COUNTER 这个变量的时候,设置的 volatile 关键字给去掉,重新运行后发现:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Incrementing COUNTER to : <span class="number">1</span></span><br><span class="line">Incrementing COUNTER to : <span class="number">2</span></span><br><span class="line">Incrementing COUNTER to : <span class="number">3</span></span><br><span class="line">Incrementing COUNTER to : <span class="number">4</span></span><br><span class="line">Incrementing COUNTER to : <span class="number">5</span></span><br></pre></td></tr></table></figure></p><p>这个时候,ChangeListener 又是一个忙等待的循环,它尝试不停地获取 COUNTER 的值,这样就会从<code>当前线程的“Cache”里面获取</code>。于是,这个线程就没有时间从主内存里面同步更新后的 COUNTER 值。这样,它就一直卡死在 COUNTER=0 的死循环上了。</p><h4 id="Case-3"><a href="#Case-3" class="headerlink" title="Case 3"></a>Case 3</h4><p>再对程序做一个小的修改。我们不再让 ChangeListener 进行完全的忙等待,而是在 while 循环里面,Sleep 5 毫秒,看看会发生什么情况。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">ChangeListener</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> threadValue = COUNTER;</span><br><span class="line"> <span class="keyword">while</span> ( threadValue < <span class="number">5</span>){</span><br><span class="line"> <span class="keyword">if</span>( threadValue!= COUNTER){</span><br><span class="line"> System.out.println(<span class="string">"Sleep 5ms, Got Change for COUNTER : "</span> + COUNTER + <span class="string">""</span>);</span><br><span class="line"> threadValue= COUNTER;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread.sleep(<span class="number">5</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) { e.printStackTrace(); }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>运行结果:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Incrementing COUNTER to : <span class="number">1</span></span><br><span class="line">Sleep <span class="number">5</span>ms, Got Change <span class="keyword">for</span> COUNTER : <span class="number">1</span></span><br><span class="line">Incrementing COUNTER to : <span class="number">2</span></span><br><span class="line">Sleep <span class="number">5</span>ms, Got Change <span class="keyword">for</span> COUNTER : <span class="number">2</span></span><br><span class="line">Incrementing COUNTER to : <span class="number">3</span></span><br><span class="line">Sleep <span class="number">5</span>ms, Got Change <span class="keyword">for</span> COUNTER : <span class="number">3</span></span><br><span class="line">Incrementing COUNTER to : <span class="number">4</span></span><br><span class="line">Sleep <span class="number">5</span>ms, Got Change <span class="keyword">for</span> COUNTER : <span class="number">4</span></span><br><span class="line">Incrementing COUNTER to : <span class="number">5</span></span><br><span class="line">Sleep <span class="number">5</span>ms, Got Change <span class="keyword">for</span> COUNTER : <span class="number">5</span></span><br></pre></td></tr></table></figure></p><p>解释:<br>虽然没有使用 volatile 关键字强制保证数据的一致性,但是短短 5ms 的 Thead.Sleep 的线程会让出CPU,线程被唤醒后才会去重新加载变量。它也就有机会把最新的数据从主内存同步到自己的高速缓存里面了。于是,ChangeListener 在下一次查看 COUNTER 值的时候,就能看到 ChangeMaker 造成的变化了。</p><p>虽然 JMM 只是 Java 虚拟机这个进程级虚拟机里的一个隔离了硬件实现的虚拟机内的抽象模型,但是这个内存模型,和计算机组成里的 CPU、高速缓存和主内存组合在一起的硬件体系非常相似。以上就是一个很好的“缓存同步”问题的示例。也就是说,如果我们的数据,在不同的线程或者 CPU 核里面去更新,因为不同的线程或 CPU 核有着各自的缓存,很有可能在 A 线程的更新,因为数据暂时不一致,在 B 线程里面是不可见的。</p>]]></content>
<summary type="html">
<p>Volatile [ˈvɑːlətl],中文解释:反复无常的,易变的,不稳定的。<br>volatile的本意是告诉编译器,此变量的值是易变的,每次读写该变量的值时务必从该变量的内存地址中读取或写入,不能为了效率使用对一个“临时”变量的读写来代替对该变量的直接读写。编译器看到了volatile关键字,就一定会生成内存访问指令,每次读写该变量就一定会执行内存访问指令直接读写该变量。若是没有volatile关键字,编译器为了效率,只会在循环开始前使用读内存指令将该变量读到寄存器中,之后在循环内都是用寄存器访问指令来操作这个“临时”变量,在循环结束后再使用内存写指令将这个寄存器中的“临时”变量写回内存。在这个过程中,如果内存中的这个变量被别的因素(其他线程、中断函数、信号处理函数、DMA控制器、其他硬件设备)所改变了,就产生数据不一致的问题。</p>
<p>volatile关键字在用C语言编写嵌入式软件里面用得很多,不使用volatile关键字的代码比使用volatile关键字的代码效率要高一些,但就无法保证数据的一致性。<br>在Java中,volatile 会确保我们对于这个变量的读取和写入,都一定会同步到主内存里,而不是从 Cache 里面读取。<br>
</summary>
<category term="Java" scheme="http://kunxiang.wang/tags/Java/"/>
</entry>
<entry>
<title>XOR异或运算在计算机中的应用</title>
<link href="http://kunxiang.wang/2020/03/28/XOR%E5%BC%82%E6%88%96%E8%BF%90%E7%AE%97%E5%9C%A8%E8%AE%A1%E7%AE%97%E6%9C%BA%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8/"/>
<id>http://kunxiang.wang/2020/03/28/XOR异或运算在计算机中的应用/</id>
<published>2020-03-28T08:41:38.000Z</published>
<updated>2020-03-28T09:10:11.907Z</updated>
<content type="html"><![CDATA[<h3 id="1-什么是异或运算"><a href="#1-什么是异或运算" class="headerlink" title="1. 什么是异或运算"></a>1. 什么是异或运算</h3><p>异或,英文为<strong>exclusive OR</strong>,缩写成xor。<br>异或(xor)是一个数学运算符。它应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“xor”。如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。</p><p>异或也叫<strong>半加运算</strong>,其运算法则相当于不带进位的二进制加法:二进制下用1表示真,0表示假,则异或的运算法则为:<strong>0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0</strong>(同为0,异为1),这些法则与加法是相同的,只是<strong>不带进位</strong>,所以异或常被认作不进位加法。<br><a id="more"></a></p><p>真值表如下:<br>|A|B|A XOR B|<br>| — | — | — |<br>|0|0|0|<br>|0|1|1|<br>|1|1|0|<br>|1|0|0|</p><h3 id="2-异或运算的特性"><a href="#2-异或运算的特性" class="headerlink" title="2. 异或运算的特性"></a>2. 异或运算的特性</h3><ul><li>交换律:<strong>A⊕B = B⊕A</strong></li><li>结合律:<strong>A⊕(B⊕C) = (A⊕B)⊕C</strong></li><li>恒等律:<strong>X⊕0 = X</strong></li><li>归零律:<strong>X⊕X = 0</strong></li><li>自反律:<strong>A⊕B⊕B = A⊕(B⊕B) = A⊕0 = A</strong></li></ul><h3 id="3-XOR在计算机中的应用"><a href="#3-XOR在计算机中的应用" class="headerlink" title="3. XOR在计算机中的应用"></a>3. XOR在计算机中的应用</h3><h5 id="3-1-快速比较两值是否想等"><a href="#3-1-快速比较两值是否想等" class="headerlink" title="3.1. 快速比较两值是否想等"></a>3.1. 快速比较两值是否想等</h5><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">r = a xor b</span><br><span class="line"><span class="keyword">if</span> r==<span class="number">0</span> </span><br><span class="line"> print(“a == b”)</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"> print(“a != <span class="string">b")</span></span><br></pre></td></tr></table></figure><h5 id="3-2-检验一个数字中1的个数的奇偶(奇偶校验)"><a href="#3-2-检验一个数字中1的个数的奇偶(奇偶校验)" class="headerlink" title="3.2. 检验一个数字中1的个数的奇偶(奇偶校验)"></a>3.2. 检验一个数字中1的个数的奇偶(奇偶校验)</h5><blockquote><p>求10100001中1的个数<br>1 ^ 0 ^ 1 ^ 0 ^ 0 ^ 0 ^ 0 ^ 1 = 1<br>按位进行异或运算得到的结果等于1,结果为奇数,得到的结果为0,结果为偶数</p></blockquote><h5 id="3-3-不使用中间变量,交换两个变量的值"><a href="#3-3-不使用中间变量,交换两个变量的值" class="headerlink" title="3.3. 不使用中间变量,交换两个变量的值"></a>3.3. 不使用中间变量,交换两个变量的值</h5><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">a = a ^ b;</span><br><span class="line">b = a ^ b; //a ^ b ^ b = a ^ <span class="number">0</span> = a;</span><br><span class="line">a = a ^ b;</span><br></pre></td></tr></table></figure><h5 id="3-4-面试题:一个整型数组里除了一个数字之外,其他的数字都出现了两次,找出这个数字"><a href="#3-4-面试题:一个整型数组里除了一个数字之外,其他的数字都出现了两次,找出这个数字" class="headerlink" title="3.4. 面试题:一个整型数组里除了一个数字之外,其他的数字都出现了两次,找出这个数字"></a>3.4. 面试题:一个整型数组里除了一个数字之外,其他的数字都出现了两次,找出这个数字</h5><p>利用异或运算的归零律:X⊕X = 0 和恒等律:X⊕0 = X</p><blockquote><p>对于数组{a, a, b, b, c, c, d},找出只出现了一次的数字d<br>a^a^b^b^c^c^d<br>= 0^0^0^d<br>= 0^d<br>= d<br>时间复杂度为O(N), 空间复杂度为O(1)</p></blockquote><h5 id="3-5-密码学中对称加密解密"><a href="#3-5-密码学中对称加密解密" class="headerlink" title="3.5. 密码学中对称加密解密"></a>3.5. 密码学中对称加密解密</h5><p>利用异或运算的自反律: A⊕B⊕B = A⊕(B⊕B) = A⊕0 = A</p><blockquote><p>message XOR key // cipherText<br>cipherText XOR key // message<br>明文 XOR 密钥 –> 密文<br>密文 XOR 密钥 –> 明文</p></blockquote><p>以上特性很好地对应了加密和解密的过程。所以目前很多加密算法都利用了异或算法的这个特性来做最后的密文打乱的工作。</p>]]></content>
<summary type="html">
<h3 id="1-什么是异或运算"><a href="#1-什么是异或运算" class="headerlink" title="1. 什么是异或运算"></a>1. 什么是异或运算</h3><p>异或,英文为<strong>exclusive OR</strong>,缩写成xor。<br>异或(xor)是一个数学运算符。它应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“xor”。如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。</p>
<p>异或也叫<strong>半加运算</strong>,其运算法则相当于不带进位的二进制加法:二进制下用1表示真,0表示假,则异或的运算法则为:<strong>0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0</strong>(同为0,异为1),这些法则与加法是相同的,只是<strong>不带进位</strong>,所以异或常被认作不进位加法。<br>
</summary>
</entry>
<entry>
<title>Python实现一个计时功能的装饰器</title>
<link href="http://kunxiang.wang/2020/03/01/Python%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AA%E8%AE%A1%E6%97%B6%E5%8A%9F%E8%83%BD%E7%9A%84%E8%A3%85%E9%A5%B0%E5%99%A8/"/>
<id>http://kunxiang.wang/2020/03/01/Python实现一个计时功能的装饰器/</id>
<published>2020-03-01T14:35:00.000Z</published>
<updated>2020-03-01T15:02:47.369Z</updated>
<content type="html"><![CDATA[<p>下面的装饰器clock会打印函数的运行时间</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># descrbe.py</span></span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">import</span> functools</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">clock</span><span class="params">(func)</span>:</span></span><br><span class="line"> <span class="string">"""this is outer clock function"""</span></span><br><span class="line"></span><br><span class="line"><span class="meta"> @functools.wraps(func) # --> 4</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">clocked</span><span class="params">(*args, **kwargs)</span>:</span> <span class="comment"># -- 1</span></span><br><span class="line"> <span class="string">"""this is inner clocked function"""</span></span><br><span class="line"> start_time = time.time()</span><br><span class="line"> result = func(*args, **kwargs) <span class="comment"># --> 2</span></span><br><span class="line"> time_cost = time.time() - start_time</span><br><span class="line"> print(func.__name__ + <span class="string">" func time_cost -> {}"</span>.format(time_cost))</span><br><span class="line"> <span class="keyword">return</span> result</span><br><span class="line"> <span class="keyword">return</span> clocked <span class="comment"># --> 3</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@functools.lru_cache() # --> 5</span></span><br><span class="line"><span class="meta">@clock # --> 6</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">fib</span><span class="params">(n)</span>:</span></span><br><span class="line"> <span class="string">"""this is fibonacci function"""</span></span><br><span class="line"> <span class="keyword">return</span> n <span class="keyword">if</span> n < <span class="number">2</span> <span class="keyword">else</span> fib(n - <span class="number">1</span>) + fib(n - <span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</span><br><span class="line"> <span class="comment"># 如果有 @functools.wraps(func) # --> 4 大多数情况下我们希望的输出是这样的</span></span><br><span class="line"> fib(<span class="number">1</span>) <span class="comment"># 输出 fib func time_cost -> 9.5367431640625e-07</span></span><br><span class="line"> print(fib.__name__) <span class="comment"># 输出 fib</span></span><br><span class="line"> print(fib.__doc__) <span class="comment"># 输出 this is fibonacci function</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 如果没有@functools.wraps(func) # --> 4</span></span><br><span class="line"> fib(<span class="number">1</span>) <span class="comment"># 输出 fib func time_cost -> 9.5367431640625e-07</span></span><br><span class="line"> print(fib.__name__) <span class="comment"># 输出 clocked</span></span><br><span class="line"> print(fib.__doc__) <span class="comment"># 输出 this is inner clocked function</span></span><br></pre></td></tr></table></figure><a id="more"></a><ol><li>定义了一个内部函数clocked,它接受任意定位参数以及关键字参数。</li><li>这行代码可用,是因为clocked的闭包中包含了自由变量func。</li><li>返回内部的函数,取代被装饰的函数。</li><li>functools.wraps是标准库中拿来即用的装饰器之一,它的作用是协助构建行为良好的装饰器。如果不加<code>functools.wraps(func)</code>, 会遮盖被装饰函数的<code>__name__</code>和<code>__doc__</code>属性,</li><li><p>functools.lru_cache()是非常实用的装饰器,它实现了备忘(memoization)功能。这是一项优化技术,它把耗时的函数的结果保存起来,避免传入相同的参数时重复计算。LRU三个字母是“Least Recently Used”的缩写,表明缓存不会无限制增长,一段时间不用的缓存条目会被扔掉。这样就会显著提高程序的运行效率。lru_cache可以使用两个可选的参数来配置。它的方法签名是<code>lru_cache(maxsize=128, typed=False)</code>。maxsize参数指定存储多少个调用的结果。缓存满了之后,旧的结果会被扔掉,腾出空间。为了得到最佳性能,maxsize应该设为2的幂。typed参数如果设为True,把不同参数类型得到的结果分开保存,即把通常认为相等的浮点数和整数参数(如 1 和 1.0)区分开。顺便说一下,因为lru_cache使用字典存储结果,而且键根据调用时传入的定位参数和关键字参数创建,所以被lru_cache装饰的函数,它的所有参数都必须是可散列的。</p></li><li><p>实际上该处的工作原理如下:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@clock # --> 6</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">fib</span><span class="params">(n)</span>:</span></span><br><span class="line"> <span class="string">"""this is fibonacci function"""</span></span><br><span class="line"> <span class="keyword">return</span> n <span class="keyword">if</span> n < <span class="number">2</span> <span class="keyword">else</span> fib(n - <span class="number">1</span>) + fib(n - <span class="number">2</span>)</span><br></pre></td></tr></table></figure></li></ol><p>等价于<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fib = clock(fib)</span><br></pre></td></tr></table></figure></p><p>fib会作为func参数传给clock。然后,clock函数会返回clocked函数,Python解释器在背后会把 clocked赋值给fib。实际上如果我们没有添加<a href="mailto:`@functools.wraps" target="_blank" rel="noopener">`@functools.wraps</a>(func)`,我们在ipython中导入describe进一步观察:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">In [<span class="number">1</span>]: <span class="keyword">import</span> describe </span><br><span class="line">In [<span class="number">2</span>]: describe.fib.__name__ </span><br><span class="line">Out[<span class="number">2</span>]: <span class="string">'clocked'</span></span><br></pre></td></tr></table></figure><p>所以,现在fib保存的是 clocked 函数的引用。自此之后,每次调用 fib(n),执行的都是 clocked(n)。clocked 大致做了下面几件事。<br>(1) 记录初始时间 t0。<br>(2) 调用原来的 fib 函数,保存结果。<br>(3) 计算经过的时间。<br>(4) 打印出来格式化收集的数据<br>(5) 返回第 2 步保存的结果。<br>这是装饰器的典型行为:把被装饰的函数替换成新函数,二者接受相同的参数,而且(通常)返回被装饰的函数本该返回的值,同时还会做些额外操作。</p>]]></content>
<summary type="html">
<p>下面的装饰器clock会打印函数的运行时间</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># descrbe.py</span></span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">import</span> functools</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">clock</span><span class="params">(func)</span>:</span></span><br><span class="line"> <span class="string">"""this is outer clock function"""</span></span><br><span class="line"></span><br><span class="line"><span class="meta"> @functools.wraps(func) # --&gt; 4</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">clocked</span><span class="params">(*args, **kwargs)</span>:</span> <span class="comment"># -- 1</span></span><br><span class="line"> <span class="string">"""this is inner clocked function"""</span></span><br><span class="line"> start_time = time.time()</span><br><span class="line"> result = func(*args, **kwargs) <span class="comment"># --&gt; 2</span></span><br><span class="line"> time_cost = time.time() - start_time</span><br><span class="line"> print(func.__name__ + <span class="string">" func time_cost -&gt; &#123;&#125;"</span>.format(time_cost))</span><br><span class="line"> <span class="keyword">return</span> result</span><br><span class="line"> <span class="keyword">return</span> clocked <span class="comment"># --&gt; 3</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@functools.lru_cache() # --&gt; 5</span></span><br><span class="line"><span class="meta">@clock # --&gt; 6</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">fib</span><span class="params">(n)</span>:</span></span><br><span class="line"> <span class="string">"""this is fibonacci function"""</span></span><br><span class="line"> <span class="keyword">return</span> n <span class="keyword">if</span> n &lt; <span class="number">2</span> <span class="keyword">else</span> fib(n - <span class="number">1</span>) + fib(n - <span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</span><br><span class="line"> <span class="comment"># 如果有 @functools.wraps(func) # --&gt; 4 大多数情况下我们希望的输出是这样的</span></span><br><span class="line"> fib(<span class="number">1</span>) <span class="comment"># 输出 fib func time_cost -&gt; 9.5367431640625e-07</span></span><br><span class="line"> print(fib.__name__) <span class="comment"># 输出 fib</span></span><br><span class="line"> print(fib.__doc__) <span class="comment"># 输出 this is fibonacci function</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 如果没有@functools.wraps(func) # --&gt; 4</span></span><br><span class="line"> fib(<span class="number">1</span>) <span class="comment"># 输出 fib func time_cost -&gt; 9.5367431640625e-07</span></span><br><span class="line"> print(fib.__name__) <span class="comment"># 输出 clocked</span></span><br><span class="line"> print(fib.__doc__) <span class="comment"># 输出 this is inner clocked function</span></span><br></pre></td></tr></table></figure>
</summary>
<category term="Python3 进阶" scheme="http://kunxiang.wang/categories/Python3-%E8%BF%9B%E9%98%B6/"/>
<category term="Python3" scheme="http://kunxiang.wang/tags/Python3/"/>
</entry>
<entry>
<title>简谈Python3中的闭包</title>
<link href="http://kunxiang.wang/2019/12/09/%E7%AE%80%E8%B0%88Python3%E4%B8%AD%E7%9A%84%E9%97%AD%E5%8C%85/"/>
<id>http://kunxiang.wang/2019/12/09/简谈Python3中的闭包/</id>
<published>2019-12-09T15:10:14.000Z</published>
<updated>2019-12-09T15:11:36.019Z</updated>
<content type="html"><![CDATA[<blockquote><p>欢迎关注微信公众号:CodeWorks<br>问题或建议,请公众号留言,欢迎<code>非抬杠式</code>讨论</p></blockquote><p>闭包是指<strong>延伸了作用域</strong>的函数,其中包含函数定义体中引用、但是不在定义体中定义的<code>非全局变量</code>。<br>闭包(closure)是函数式编程的重要的语法结构。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。</p><p>当一个内嵌函数引用其外部作用域的变量,我们就会得到一个闭包. 总结一下,<code>创建一个闭包必须满足以下几点</code>:</p><ol><li>必须有一个内嵌函数</li><li>内嵌函数必须引用外部函数中的变量</li><li>外部函数的返回值必须是内嵌函数</li></ol><p>闭包是一种函数,它会保留定义函数时存在的自由变量的绑定,这样调用函数时虽然定义作用域不可用了,但仍能使用那些绑定。</p><a id="more"></a><p>闭包的概念难以掌握,下面通过示例进行理解。</p><p>假设我们要实现一个计算<strong><code>移动平均</code></strong>功能的代码,如何实现呢?</p><p>初学者可能会用<code>类</code>来实现,如示例1:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 示例1</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Averager</span><span class="params">(object)</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line"> self.series = []</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__call__</span><span class="params">(self, new_value)</span>:</span></span><br><span class="line"> self.series.append(new_value)</span><br><span class="line"> total = sum(self.series)</span><br><span class="line"> <span class="keyword">return</span> total/len(self.series)</span><br></pre></td></tr></table></figure></p><p>Average的实例是可调用对象:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>avg = Averager()</span><br><span class="line"><span class="meta">>>> </span>avg(<span class="number">10</span>)</span><br><span class="line"><span class="number">10.0</span></span><br><span class="line"><span class="meta">>>> </span>avg(<span class="number">11</span>)</span><br><span class="line"><span class="number">10.5</span></span><br><span class="line"><span class="meta">>>> </span>avg(<span class="number">12</span>)</span><br><span class="line"><span class="number">11.0</span></span><br></pre></td></tr></table></figure></p><p>下面使用<code>函数式</code>实现,如示例2:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 示例2</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">make_averager</span><span class="params">()</span>:</span></span><br><span class="line"> series = []</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">averager</span><span class="params">(new_value)</span>:</span></span><br><span class="line"> series.append(new_value)</span><br><span class="line"> total = sum(series)</span><br><span class="line"> <span class="keyword">return</span> total/len(series)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> averager</span><br></pre></td></tr></table></figure></p><p>调用make_averager时,返回一个averager函数对象。每次调用averager时,该对象会把参数添加到series中,然后计算当前平均值,如下所示:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>avg = make_averager()</span><br><span class="line"><span class="meta">>>> </span>avg(<span class="number">10</span>)</span><br><span class="line"><span class="number">10.0</span></span><br><span class="line"><span class="meta">>>> </span>avg(<span class="number">11</span>)</span><br><span class="line"><span class="number">10.5</span></span><br><span class="line"><span class="meta">>>> </span>avg(<span class="number">12</span>)</span><br><span class="line"><span class="number">11.0</span></span><br></pre></td></tr></table></figure></p><p>以上两个示例有共通之处:调用Averager()或make_averager()得到一个可调用对象avg,该对象会更新历史值,然后计算当前均值。示例1中,avg是Averager的实例;实例2中是内部函数averager。不管怎样,我们都只需要调用avg(n),把n放入系列值series中,然后重新计算均值。</p><p>Averager()类的实例avg在哪里存储历史值很明显,<code>但是第二个示例中的avg函数在哪里寻找series呢</code>?</p><p>注意,series是make_averager函数的局部变量,因为那个函数的定义体中初始化了<code>series = []</code>。可是,调用avg(10)时,make_averager函数已经返回了,而他的本地作用域也一去不复返了。</p><p>在averager函数中,series是<code>自由变量</code>,指未在本地作用域中绑定的变量,图形化展示如下:<br><img src="https://upload-images.jianshu.io/upload_images/2952111-3249d24d6da9aa8b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="闭包"></p><p><strong>averager的闭包延伸到那个函数的作用域之外,包含对自由变量series的绑定</strong></p><p>我们可以审查返回的averager对象,发现Python在<code>__code__</code>属性(表示编译后的函数定义体)中保存局部变量和自由变量的名称,如下所示</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 审查make_averager创建的函数</span></span><br><span class="line"><span class="meta">>>> </span>avg.__code__.co_varnames</span><br><span class="line">(<span class="string">'new_value'</span>, <span class="string">'total'</span>)</span><br><span class="line"><span class="meta">>>> </span>avg.__code__.co_freevars</span><br><span class="line">(<span class="string">'series'</span>,)</span><br></pre></td></tr></table></figure><p>series绑定在返回的avg函数的<code>__closure__</code>属性中。<code>avg.__closure__</code>中各个元素对应于<code>avg.__code__.co_freevars</code>中的一个名称。这些元素是cell对象,有个<code>cell_content</code>属性,保存着真正的值。这些属性的值如示例所示:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>avg.__code__.co_freevars</span><br><span class="line">(<span class="string">'series'</span>,)</span><br><span class="line"><span class="meta">>>> </span>avg.__closure__</span><br><span class="line">(<cell at <span class="number">0x108b89828</span>: list object at <span class="number">0x108ae96c8</span>>,)</span><br><span class="line"><span class="meta">>>> </span>avg.__closure__[<span class="number">0</span>].cell_contents</span><br><span class="line">[<span class="number">10</span>,<span class="number">11</span>,<span class="number">12</span>]</span><br></pre></td></tr></table></figure></p><p>综上,<code>闭包是一种函数,它会保留定义函数时存在的自由变量的绑定,这样调用函数时虽然定义作用域不可用了,但仍能使用那些绑定</code>。</p><p>稍微有点编程经验的人会看到,我们实现的计算移动平均值得方法实际上有很大的改进空间,在后面的介绍中会进行改进。</p>]]></content>
<summary type="html">
<blockquote>
<p>欢迎关注微信公众号:CodeWorks<br>问题或建议,请公众号留言,欢迎<code>非抬杠式</code>讨论</p>
</blockquote>
<p>闭包是指<strong>延伸了作用域</strong>的函数,其中包含函数定义体中引用、但是不在定义体中定义的<code>非全局变量</code>。<br>闭包(closure)是函数式编程的重要的语法结构。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。</p>
<p>当一个内嵌函数引用其外部作用域的变量,我们就会得到一个闭包. 总结一下,<code>创建一个闭包必须满足以下几点</code>:</p>
<ol>
<li>必须有一个内嵌函数</li>
<li>内嵌函数必须引用外部函数中的变量</li>
<li>外部函数的返回值必须是内嵌函数</li>
</ol>
<p>闭包是一种函数,它会保留定义函数时存在的自由变量的绑定,这样调用函数时虽然定义作用域不可用了,但仍能使用那些绑定。</p>
</summary>
<category term="Python3 进阶" scheme="http://kunxiang.wang/categories/Python3-%E8%BF%9B%E9%98%B6/"/>
<category term="Python3 闭包" scheme="http://kunxiang.wang/categories/Python3-%E8%BF%9B%E9%98%B6/Python3-%E9%97%AD%E5%8C%85/"/>
<category term="Python3" scheme="http://kunxiang.wang/tags/Python3/"/>
</entry>
<entry>
<title>简述Python中变量作用域的规则</title>
<link href="http://kunxiang.wang/2019/12/07/%E7%AE%80%E8%BF%B0Python%E4%B8%AD%E5%8F%98%E9%87%8F%E4%BD%9C%E7%94%A8%E5%9F%9F%E7%9A%84%E8%A7%84%E5%88%99/"/>
<id>http://kunxiang.wang/2019/12/07/简述Python中变量作用域的规则/</id>
<published>2019-12-07T15:22:52.000Z</published>
<updated>2019-12-10T01:42:49.633Z</updated>
<content type="html"><![CDATA[<p>介绍这一题目的目的是引出python中较为高级的话题—闭包和装饰器。</p><p>在下面的例子中,定义并测试一个函数,它读取两个变量的值:一个是局部变量a,是函数的参数; 另一个是变量b,这个函数没有定义它。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span><span class="function"><span class="keyword">def</span> <span class="title">f1</span><span class="params">(a)</span>:</span></span><br><span class="line"><span class="meta">... </span> print(a)</span><br><span class="line"><span class="meta">... </span> print(b)</span><br><span class="line">...</span><br><span class="line"><span class="meta">>>> </span>f1(<span class="number">1</span>)</span><br><span class="line"><span class="number">1</span></span><br><span class="line">Traceback (most recent call last):</span><br><span class="line"> File <span class="string">"<stdin>"</span>, line <span class="number">1</span>, <span class="keyword">in</span> <module></span><br><span class="line"> File <span class="string">"<stdin>"</span>, line <span class="number">3</span>, <span class="keyword">in</span> f1</span><br><span class="line">NameError: name <span class="string">'b'</span> <span class="keyword">is</span> <span class="keyword">not</span> defined</span><br></pre></td></tr></table></figure><p>出现此结果完全在意料范围内,因为我们压根从来没有定义过变量b。如果我们在调用函数f1前定义变量b,那么不会存在问题,因为此处的b是<code>全局变量</code>。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>b=<span class="number">2</span></span><br><span class="line"><span class="meta">>>> </span>f1(<span class="number">1</span>)</span><br><span class="line"><span class="number">1</span></span><br><span class="line"><span class="number">2</span></span><br></pre></td></tr></table></figure><p>下面来一个较为特殊的例子<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>b=<span class="number">2</span></span><br><span class="line"><span class="meta">>>> </span><span class="function"><span class="keyword">def</span> <span class="title">f2</span><span class="params">(a)</span>:</span></span><br><span class="line"><span class="meta">... </span> print(a)</span><br><span class="line"><span class="meta">... </span> print(b)</span><br><span class="line"><span class="meta">... </span> b=<span class="number">3</span></span><br><span class="line">...</span><br><span class="line"><span class="meta">>>> </span>f2(<span class="number">1</span>)</span><br><span class="line"><span class="number">1</span></span><br><span class="line">Traceback (most recent call last):</span><br><span class="line"> File <span class="string">"<stdin>"</span>, line <span class="number">1</span>, <span class="keyword">in</span> <module></span><br><span class="line"> File <span class="string">"<stdin>"</span>, line <span class="number">3</span>, <span class="keyword">in</span> f2</span><br><span class="line">UnboundLocalError: local variable <span class="string">'b'</span> referenced before assignment</span><br></pre></td></tr></table></figure></p><p>可以看到在赋值之前,第二个print失败了,<code>提示局部变量b在赋值前被引用了</code>。</p><p>实际上,Python 编译函数的定义体时,它判断 b 是局部变量,因为在函数中给它赋值了。生成的字节码证实了这种判断(后面会讨论),Python 会尝试从本地环境获取 b。后面调用f2(1)时,f2的定义体会获取并打印局部变量 a 的值,但是尝试获取局部变量 b 的值时,发现 b 没有绑定值。</p><p>这是Python的设计选择:Python不要求声明变量类型,但是默认在函数定义体中赋值的变量是局部变量。如果在函数中赋值时想让解释器把 b 当成全局变量,要使用 <code>global</code> 声明:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>b=<span class="number">2</span></span><br><span class="line"><span class="meta">>>> </span><span class="function"><span class="keyword">def</span> <span class="title">f3</span><span class="params">(a)</span>:</span></span><br><span class="line"><span class="meta">... </span> <span class="keyword">global</span> b</span><br><span class="line"><span class="meta">... </span> print(a)</span><br><span class="line"><span class="meta">... </span> print(b)</span><br><span class="line"><span class="meta">... </span> b=<span class="number">3</span></span><br><span class="line">...</span><br><span class="line"><span class="meta">>>> </span>f3(<span class="number">1</span>)</span><br><span class="line"><span class="number">1</span></span><br><span class="line"><span class="number">2</span></span><br><span class="line"><span class="meta">>>> </span>b</span><br><span class="line"><span class="number">3</span></span><br><span class="line"><span class="meta">>>> </span>f3(<span class="number">1</span>)</span><br><span class="line"><span class="number">1</span></span><br><span class="line"><span class="number">3</span></span><br><span class="line"><span class="meta">>>> </span>b=<span class="number">30</span></span><br><span class="line"><span class="meta">>>> </span>b</span><br><span class="line"><span class="number">30</span></span><br><span class="line"><span class="meta">>>> </span>f3(<span class="number">1</span>)</span><br><span class="line"><span class="number">1</span></span><br><span class="line"><span class="number">30</span></span><br></pre></td></tr></table></figure></p><p>接下来,我们看一下f1和f2的字节码:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>dis(f1)</span><br><span class="line"> <span class="number">2</span> <span class="number">0</span> LOAD_GLOBAL <span class="number">0</span> (<span class="keyword">print</span>) >>> <span class="number">1</span></span><br><span class="line"> <span class="number">2</span> LOAD_FAST <span class="number">0</span> (a) >>> <span class="number">2</span></span><br><span class="line"> <span class="number">4</span> CALL_FUNCTION <span class="number">1</span></span><br><span class="line"> <span class="number">6</span> POP_TOP</span><br><span class="line"></span><br><span class="line"> <span class="number">3</span> <span class="number">8</span> LOAD_GLOBAL <span class="number">0</span> (<span class="keyword">print</span>)</span><br><span class="line"> <span class="number">10</span> LOAD_GLOBAL <span class="number">1</span> (b) >>> <span class="number">3</span></span><br><span class="line"> <span class="number">12</span> CALL_FUNCTION <span class="number">1</span></span><br><span class="line"> <span class="number">14</span> POP_TOP</span><br><span class="line"> <span class="number">16</span> LOAD_CONST <span class="number">0</span> (<span class="keyword">None</span>)</span><br><span class="line"> <span class="number">18</span> RETURN_VALUE</span><br><span class="line"><span class="meta">>>> </span>dis(f2)</span><br><span class="line"> <span class="number">2</span> <span class="number">0</span> LOAD_GLOBAL <span class="number">0</span> (<span class="keyword">print</span>)</span><br><span class="line"> <span class="number">2</span> LOAD_FAST <span class="number">0</span> (a)</span><br><span class="line"> <span class="number">4</span> CALL_FUNCTION <span class="number">1</span></span><br><span class="line"> <span class="number">6</span> POP_TOP</span><br><span class="line"></span><br><span class="line"> <span class="number">3</span> <span class="number">8</span> LOAD_GLOBAL <span class="number">0</span> (<span class="keyword">print</span>)</span><br><span class="line"> <span class="number">10</span> LOAD_FAST <span class="number">1</span> (b) >>> <span class="number">4</span></span><br><span class="line"> <span class="number">12</span> CALL_FUNCTION <span class="number">1</span></span><br><span class="line"> <span class="number">14</span> POP_TOP</span><br><span class="line"></span><br><span class="line"> <span class="number">4</span> <span class="number">16</span> LOAD_CONST <span class="number">1</span> (<span class="number">3</span>)</span><br><span class="line"> <span class="number">18</span> STORE_FAST <span class="number">1</span> (b)</span><br><span class="line"> <span class="number">20</span> LOAD_CONST <span class="number">0</span> (<span class="keyword">None</span>)</span><br><span class="line"> <span class="number">22</span> RETURN_VALUE</span><br></pre></td></tr></table></figure></p><p><img src="https://upload-images.jianshu.io/upload_images/2952111-8e292da51753cfef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="Screen Shot 2019-12-07 at 17.10.03.png"></p><p>对于f1函数的反汇编:</p><ol><li>LOAD_GLOBAL加载全局名称 print。</li><li>LOAD_FAST加载本地名称 a。</li><li>LOAD_GLOBAL加载全局名称 b。</li></ol><p>对于f2函数的反汇编:</p><ol><li>LOAD_FAST加载本地名称 b。这表明,编译器把 b 视作<code>局部变量</code>,即使在后面才为 b 赋值。</li></ol><p>对于函数f3的反汇编如下图所示,可以看到变量b为全局变量。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>dis(f3)</span><br><span class="line"> <span class="number">3</span> <span class="number">0</span> LOAD_GLOBAL <span class="number">0</span> (<span class="keyword">print</span>)</span><br><span class="line"> <span class="number">2</span> LOAD_FAST <span class="number">0</span> (a)</span><br><span class="line"> <span class="number">4</span> CALL_FUNCTION <span class="number">1</span></span><br><span class="line"> <span class="number">6</span> POP_TOP</span><br><span class="line"></span><br><span class="line"> <span class="number">4</span> <span class="number">8</span> LOAD_GLOBAL <span class="number">0</span> (<span class="keyword">print</span>)</span><br><span class="line"> <span class="number">10</span> LOAD_GLOBAL <span class="number">1</span> (b) >>> ***</span><br><span class="line"> <span class="number">12</span> CALL_FUNCTION <span class="number">1</span></span><br><span class="line"> <span class="number">14</span> POP_TOP</span><br><span class="line"></span><br><span class="line"> <span class="number">5</span> <span class="number">16</span> LOAD_CONST <span class="number">1</span> (<span class="number">3</span>)</span><br><span class="line"> <span class="number">18</span> STORE_GLOBAL <span class="number">1</span> (b)</span><br><span class="line"> <span class="number">20</span> LOAD_CONST <span class="number">0</span> (<span class="keyword">None</span>)</span><br><span class="line"> <span class="number">22</span> RETURN_VALUE</span><br></pre></td></tr></table></figure><p><img src="https://upload-images.jianshu.io/upload_images/2952111-9f820de0acd3270c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="Screen Shot 2019-12-07 at 17.30.33.png"></p><p>至此,我们可以基本了解python函数中变量作用域的问题,这将为后面介绍的闭包和装饰器的学习打下基础。</p><hr>]]></content>
<summary type="html">
<p>介绍这一题目的目的是引出python中较为高级的话题—闭包和装饰器。</p>
<p>在下面的例子中,定义并测试一个函数,它读取两个变量的值:一个是局部变量a,是函数的参数; 另一个是变量b,这个函数没有定义它。</p>
<figure class="highlight py
</summary>
<category term="Python3 进阶" scheme="http://kunxiang.wang/categories/Python3-%E8%BF%9B%E9%98%B6/"/>
<category term="Python3 闭包" scheme="http://kunxiang.wang/categories/Python3-%E8%BF%9B%E9%98%B6/Python3-%E9%97%AD%E5%8C%85/"/>
<category term="Python3" scheme="http://kunxiang.wang/tags/Python3/"/>
</entry>
<entry>
<title>用Emoji解释编程语言中的map、filter、reduce</title>
<link href="http://kunxiang.wang/2019/11/27/%E7%94%A8Emoji%E8%A7%A3%E9%87%8A%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%E4%B8%AD%E7%9A%84map%E3%80%81filter%E3%80%81reduce/"/>
<id>http://kunxiang.wang/2019/11/27/用Emoji解释编程语言中的map、filter、reduce/</id>
<published>2019-11-27T08:44:01.000Z</published>
<updated>2019-11-27T08:45:59.105Z</updated>
<content type="html"><![CDATA[<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">map(cook, [🌽, 🥔, 🐥, 🐮])</span><br><span class="line">===> [🍿, 🍟, 🍗, 🥩]</span><br><span class="line"></span><br><span class="line">filter(isMeat, [🍿, 🍟, 🍗, 🥩])</span><br><span class="line">===> [🍗, 🥩]</span><br><span class="line"></span><br><span class="line">reduce(afterEat, [🍿, 🍟, 🍗, 🥩])</span><br><span class="line">===> 💩</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line
</summary>
<category term="Funny" scheme="http://kunxiang.wang/categories/Funny/"/>
<category term="Funny" scheme="http://kunxiang.wang/tags/Funny/"/>
</entry>
<entry>
<title>如何优雅滴在手机上跑Python代码</title>
<link href="http://kunxiang.wang/2019/11/15/%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E6%BB%B4%E5%9C%A8%E6%89%8B%E6%9C%BA%E4%B8%8A%E8%B7%91Python%E4%BB%A3%E7%A0%81/"/>
<id>http://kunxiang.wang/2019/11/15/如何优雅滴在手机上跑Python代码/</id>
<published>2019-11-15T01:10:12.000Z</published>
<updated>2019-11-15T09:13:47.266Z</updated>
<content type="html"><![CDATA[<p>本文重点围绕苹果设备,给大家描述一下小编自己如何在苹果移动设备上玩转Python代码的。按照推荐指数由高到低给大家推荐相关工具。</p><h3 id="Pythonista"><a href="#Pythonista" class="headerlink" title="Pythonista"></a>Pythonista</h3><p>与一般的python移动端软件不同,它是一款安装在手机上的Python IDE软件,推荐指数4.5星。扣掉的0.5星是因为软件略贵(9.99刀)。</p><p>该软件可以在苹果移动设备上提供几乎完整的Python开发环境,软件里有很多的demo程序,包括了游戏、数据处理、图片处理等。说实话,本人觉得光这些demo代码就值这个价格了。软件除了支持标准Python库以外,还支持很多常用的三方库,例如用于科学计算的Numpy和绘图包matplotlib、用于http请求的Requests等。另外,我们还可以在软件中写脚本调用手机接口,获得接切板、联系人、位置信息等,功能狠强大,等待盆友萌前去体验。<br><img src="https://img-blog.csdnimg.cn/20191115114946949.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTUyMjQ0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><a id="more"></a><h3 id="Python-ai"><a href="#Python-ai" class="headerlink" title="Python ai"></a>Python ai</h3><p>这款软件可以给4.4颗星,也是一款非常优秀的软件。说其优秀,体现在这么几点:</p><ul><li>软件免费,没有广告,实在是情怀良心之作</li><li>离线IDE环境</li><li>支持很多科学计算的三方库</li><li>支持pip安装三方库<br><img src="https://img-blog.csdnimg.cn/20191115115022887.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTUyMjQ0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></li></ul><h3 id="Pydriod"><a href="#Pydriod" class="headerlink" title="Pydriod"></a>Pydriod</h3><p>就Python IDE来说,安卓端的软件跟苹果端软件相比还是差的挺多的。此处推荐Pydriod,给4颗星吧。貌似很多应用商店找不到,如果可以顺利FQ,推荐去Google Play下载。</p><p><img src="https://img-blog.csdnimg.cn/20191115115210695.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTUyMjQ0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>再次强调一下,移动端Python IDE软件有很多,对于苹果端,小编大部分已经下载体验过,自认为还是很有发言权的,此处推荐的都是<strong>本地IDE</strong>的能如我法眼的Python软件。其实还有一些软件使用的是<strong>远程IDE</strong>,例如苹果和安卓端的PythonJam,体验还算OK,感兴趣大家可以下载尝试。</p>]]></content>
<summary type="html">
<p>本文重点围绕苹果设备,给大家描述一下小编自己如何在苹果移动设备上玩转Python代码的。按照推荐指数由高到低给大家推荐相关工具。</p>
<h3 id="Pythonista"><a href="#Pythonista" class="headerlink" title="Pythonista"></a>Pythonista</h3><p>与一般的python移动端软件不同,它是一款安装在手机上的Python IDE软件,推荐指数4.5星。扣掉的0.5星是因为软件略贵(9.99刀)。</p>
<p>该软件可以在苹果移动设备上提供几乎完整的Python开发环境,软件里有很多的demo程序,包括了游戏、数据处理、图片处理等。说实话,本人觉得光这些demo代码就值这个价格了。软件除了支持标准Python库以外,还支持很多常用的三方库,例如用于科学计算的Numpy和绘图包matplotlib、用于http请求的Requests等。另外,我们还可以在软件中写脚本调用手机接口,获得接切板、联系人、位置信息等,功能狠强大,等待盆友萌前去体验。<br><img src="https://img-blog.csdnimg.cn/20191115114946949.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTUyMjQ0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
</summary>
<category term="Tools" scheme="http://kunxiang.wang/categories/Tools/"/>
<category term="Tools" scheme="http://kunxiang.wang/tags/Tools/"/>
</entry>
<entry>
<title>Python中如何优雅的使用assert断言</title>
<link href="http://kunxiang.wang/2019/11/14/Python%E4%B8%AD%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E7%9A%84%E4%BD%BF%E7%94%A8assert%E6%96%AD%E8%A8%80/"/>
<id>http://kunxiang.wang/2019/11/14/Python中如何优雅的使用assert断言/</id>
<published>2019-11-14T09:04:42.000Z</published>
<updated>2019-11-15T01:10:55.336Z</updated>
<content type="html"><![CDATA[<h3 id="什么是assert断言"><a href="#什么是assert断言" class="headerlink" title="什么是assert断言"></a>什么是assert断言</h3><blockquote><p>Assert statements are a convenient way to insert debugging assertions into a program</p></blockquote><p>断言声明是用于程序调试的一个便捷方式。断言可以看做是一个debug工具,Python的实现也符合这个设计哲学,在Python中assert语句的执行是依赖于<code>__debug__</code>这个内置变量的,其默认值为<code>True</code>。当<code>__debug__</code>为<code>True</code>时,assert语句才会被执行。</p><p>对于一般的声明,assert expression等价于<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> __debug__:</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> expression: <span class="keyword">raise</span> AssertionError</span><br></pre></td></tr></table></figure></p><p>assert可以同时声明两个个expression,例如<strong>assert expression1, expression2</strong>等价于<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> __debug__:</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> expression1: <span class="keyword">raise</span> AssertionError(expression2)</span><br></pre></td></tr></table></figure></p><p>如果执行脚本文件时加上<code>-O</code>参数, <code>__debug__</code>则为<code>False</code></p><p>举一个例子,假设我们有一个脚本testAssert.py,内容为:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">print(__debug__)</span><br><span class="line"><span class="keyword">assert</span> <span class="number">1</span> > <span class="number">2</span></span><br></pre></td></tr></table></figure></p><a id="more"></a><p>当使用<code>python assert.py</code>运行时,<code>__debug__</code>会输出True,assert 1 > 2语句会抛出AssertionError异常。</p><p>当使用<code>python -O assert.py</code>运行时,<code>__debug__</code>会输出False,assert 1 > 2语句由于没有执行不会报任何异常。</p><h3 id="断言和异常的使用场景"><a href="#断言和异常的使用场景" class="headerlink" title="断言和异常的使用场景"></a>断言和异常的使用场景</h3><p>先说结论:</p><blockquote><p>检查<code>先验条件</code>使用断言,检查<code>后验条件</code>使用异常</p></blockquote><p>举个例子来说明一下,在开发中我们经常会遇到读取本地文件的场景。我们定义一个read_file方法。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">read_file</span><span class="params">(path)</span>:</span></span><br><span class="line"> <span class="keyword">assert</span> is_instance(file_path, str)</span><br><span class="line"> ...</span><br></pre></td></tr></table></figure><p>read_file函数要求在开始执行的时候满足一定条件:file_path必须是str类型,这个条件就是先验条件,如果不满足,就不能调用这个函数,如果真的出现了不满足条件的情况,证明代码中出现了bug,这时候我们就可以使用assert语句来对file_path的类型进行推断,提醒程序员修改代码,也可以使用if…raise…语句来实现assert,但是要繁琐很多。在很多优秀的Python项目中都会看到使用assert进行先验判断的情况,平时可以多多留意。</p><p>read_file函数在被调用执行后,依然需要满足一定条件,比如file_path所指定的文件需要是存在的,并且当前用户有权限读取该文件,这些条件称为后验条件,对于后验条件的检查,我们需要使用异常来处理。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">read_file</span><span class="params">(file_path)</span>:</span></span><br><span class="line"> <span class="keyword">assert</span> isinstance(file_path, str)</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> check_exist(file_path):</span><br><span class="line"> <span class="keyword">raise</span> FileNotFoundError()</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> has_privilege(file_path):</span><br><span class="line"> <span class="keyword">raise</span> PermissionError()</span><br></pre></td></tr></table></figure><p>文件不存在和没有权限,这两种情况并不属于代码bug,是代码逻辑的一部分,上层代码捕获异常后可能会执行其他逻辑,因此我们不能接受这部分代码在生产环境中被忽略。并且,相比于assert语句只能抛出AssertionError,使用异常可以抛出更详细的错误,方便上层代码针对不同错误执行不同的逻辑。</p><hr><p><a href="https://juejin.im/post/5af02413f265da0b776f9e15" target="_blank" rel="noopener">参考链接</a></p>]]></content>
<summary type="html">
<h3 id="什么是assert断言"><a href="#什么是assert断言" class="headerlink" title="什么是assert断言"></a>什么是assert断言</h3><blockquote>
<p>Assert statements are a convenient way to insert debugging assertions into a program</p>
</blockquote>
<p>断言声明是用于程序调试的一个便捷方式。断言可以看做是一个debug工具,Python的实现也符合这个设计哲学,在Python中assert语句的执行是依赖于<code>__debug__</code>这个内置变量的,其默认值为<code>True</code>。当<code>__debug__</code>为<code>True</code>时,assert语句才会被执行。</p>
<p>对于一般的声明,assert expression等价于<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> __debug__:</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> expression: <span class="keyword">raise</span> AssertionError</span><br></pre></td></tr></table></figure></p>
<p>assert可以同时声明两个个expression,例如<strong>assert expression1, expression2</strong>等价于<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> __debug__:</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> expression1: <span class="keyword">raise</span> AssertionError(expression2)</span><br></pre></td></tr></table></figure></p>
<p>如果执行脚本文件时加上<code>-O</code>参数, <code>__debug__</code>则为<code>False</code></p>
<p>举一个例子,假设我们有一个脚本testAssert.py,内容为:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">print(__debug__)</span><br><span class="line"><span class="keyword">assert</span> <span class="number">1</span> &gt; <span class="number">2</span></span><br></pre></td></tr></table></figure></p>
</summary>
<category term="Python3 进阶" scheme="http://kunxiang.wang/categories/Python3-%E8%BF%9B%E9%98%B6/"/>
<category term="Python3" scheme="http://kunxiang.wang/tags/Python3/"/>
</entry>
<entry>
<title>神经网络中为什么不能将权重初始值设置为一样的值</title>
<link href="http://kunxiang.wang/2019/11/04/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E4%B8%AD%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E8%83%BD%E5%B0%86%E6%9D%83%E9%87%8D%E5%88%9D%E5%A7%8B%E5%80%BC%E8%AE%BE%E7%BD%AE%E4%B8%BA%E4%B8%80%E6%A0%B7%E7%9A%84%E5%80%BC/"/>
<id>http://kunxiang.wang/2019/11/04/神经网络中为什么不能将权重初始值设置为一样的值/</id>
<published>2019-11-04T03:00:31.000Z</published>
<updated>2019-11-15T08:27:21.259Z</updated>
<content type="html"><![CDATA[<p>先说结论,如果权重初始值设为0的话,将无法正确进行学习。</p><p>这是因为在误差反向传播法中,所有的权重值都会进行相同的更新。比如,在2层神经网络中,假设第1层和第2层的权重为0。这样一来,正向传播时,因为输入层的权重为0,所以第2层的神经元全部会被传递相同的值。第2层的神经元中全部输入相同的值,这意味着反向传播时第2层的权重全部都会进行相同的更新。因此,权重被更新为相同的值,并拥有了对称的值(重复的值)。这使得神经网络拥有许多不同的权重的意义丧失了。为了防止“权重均一化” (严格地讲,是为了瓦解权重的对称结构),必须随机生成初始值。</p><p>实际上,考虑一个全连接的神经网络,同一层中的任意神经元是同构的,对于相同的输入他们会有同样的输出,此时如果将参数全部初始化为相同的值,那么无论前向传播还是反向传播,参数的取值还是完全相同,学习将无法打破这种对称性,最终同一网络层中的各个参数仍然是相同的。</p><p>综上,必须随机的初始化神经网络参数的值,以打破这种对称性。</p>]]></content>
<summary type="html">
<p>先说结论,如果权重初始值设为0的话,将无法正确进行学习。</p>
<p>这是因为在误差反向传播法中,所有的权重值都会进行相同的更新。比如,在2层神经网络中,假设第1层和第2层的权重为0。这样一来,正向传播时,因为输入层的权重为0,所以第2层的神经元全部会被传递相同的值。第2
</summary>
<category term="机器学习" scheme="http://kunxiang.wang/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="机器学习" scheme="http://kunxiang.wang/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="神经网络" scheme="http://kunxiang.wang/tags/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/"/>
</entry>
<entry>
<title>Git分支管理策略及简单操作</title>
<link href="http://kunxiang.wang/2019/10/10/Git%E5%88%86%E6%94%AF%E7%AE%A1%E7%90%86%E7%AD%96%E7%95%A5%E5%8F%8A%E7%AE%80%E5%8D%95%E6%93%8D%E4%BD%9C/"/>
<id>http://kunxiang.wang/2019/10/10/Git分支管理策略及简单操作/</id>
<published>2019-10-10T05:59:05.000Z</published>
<updated>2020-06-09T06:39:49.160Z</updated>
<content type="html"><![CDATA[<p>前几天整理了一下之前项目的开发代码,当时使用了Git来进行代码管理。虽然本人熟悉常用的Git操作,但是对分支的管理经验非常欠缺。拿这个项目来说,在项目中有不下20个分支,每个分支间的继承关系相当之混乱,非常不利于代码的安全管理。因此,通过在网络上的学习,总结了一下关于Git分支管理的策略方法,供后续回顾学习。</p><p>当然必须承认,代码分支管理策略有很多种,不局限于以下介绍。但是下面介绍的这个分支管理策略非常具有工程借鉴意义,几乎适用于所有开发场景。</p><table><thead><tr><th style="text-align:center">分支</th><th style="text-align:center">命名</th><th style="text-align:center">说明</th></tr></thead><tbody><tr><td style="text-align:center">主分支</td><td style="text-align:center">master</td><td style="text-align:center">主分支,所有提供给用户使用的正式版本,都在这个主分支上发布</td></tr><tr><td style="text-align:center">开发分支</td><td style="text-align:center">develop</td><td style="text-align:center">开发分支,永远是功能最新最全的分支</td></tr><tr><td style="text-align:center">功能分支</td><td style="text-align:center">feature-*</td><td style="text-align:center">新功能分支,某个功能点正在开发阶段</td></tr><tr><td style="text-align:center">发布版本</td><td style="text-align:center">release-*</td><td style="text-align:center">发布定期要上线的功能</td></tr><tr><td style="text-align:center">修复分支</td><td style="text-align:center">hotfix-*</td><td style="text-align:center">修复线上代码的 bug</td></tr></tbody></table><a id="more"></a><h3 id="1-主分支master"><a href="#1-主分支master" class="headerlink" title="1. 主分支master"></a>1. 主分支master</h3><p>首先,代码库应该有且仅有一个主分支。所有提供给用户使用的正式版本,都在这个主分支上发布。Git主分支的名字,默认叫做master。它是自动建立的,版本库初始化以后,默认就是在主分支在进行开发。团队成员从主分支(master)获得的都是处于可发布状态的代码。</p><h3 id="2-开发分支develop"><a href="#2-开发分支develop" class="headerlink" title="2. 开发分支develop"></a>2. 开发分支develop</h3><p>日常开发应该在另一条分支上完成。我们把开发用的分支,叫做develop分支。开发分支(develop)应该总能够获得最新开发进展的代码。如果想正式对外发布,就在master分支上,对develop分支进行merge。下面介绍常用的几个命令:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 在master分支上创建develop分支</span></span><br><span class="line">git checkout -b develop master</span><br><span class="line"></span><br><span class="line"><span class="comment"># 切换到master分支</span></span><br><span class="line">git checkout master</span><br><span class="line"></span><br><span class="line"><span class="comment"># 对develop分支合并到当前master分支</span></span><br><span class="line">git merge --no-ff develop</span><br></pre></td></tr></table></figure><h3 id="3-临时分支"><a href="#3-临时分支" class="headerlink" title="3. 临时分支"></a>3. 临时分支</h3><p>除了常设分支以外,还有一些临时性分支,用于应对一些特定目的的版本开发。临时性分支主要有三种:</p><ul><li>功能(feature)分支</li><li>预发布(release)分支</li><li>修补bug(bugfix)分支</li></ul><p>这三种分支都属于临时性需要,使用完以后,最好删除,使得代码库的常设分支始终只有master和develop。</p><h4 id="功能分支"><a href="#功能分支" class="headerlink" title="功能分支"></a>功能分支</h4><p>feature分支是为了开发某种特定功能,从develop分支上面分出来的。开发完成后,要再并入develop。功能分支的名字,可以采用feature-xxx的形式命名。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 从develop创建一个功能分支</span></span><br><span class="line">git checkout -b feature-x develop</span><br><span class="line"></span><br><span class="line"><span class="comment"># 开发完成后,将功能分支合并到develop分支:</span></span><br><span class="line">git checkout develop</span><br><span class="line">git merge --no-ff feature-x</span><br><span class="line"></span><br><span class="line"><span class="comment"># 删除feature分支</span></span><br><span class="line">git branch -d feature-x</span><br></pre></td></tr></table></figure></p><h4 id="预发布分支"><a href="#预发布分支" class="headerlink" title="预发布分支"></a>预发布分支</h4><p>release分支是指发布正式版本之前(即合并到master分支之前),我们可能需要有一个预发布的版本进行测试而创建的分支。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建一个预发布分支</span></span><br><span class="line">git checkout -b release-x develop</span><br><span class="line"></span><br><span class="line"><span class="comment"># 确认没有问题后,合并到master分支</span></span><br><span class="line">git checkout master</span><br><span class="line">git merge --no-ff release-x</span><br><span class="line"></span><br><span class="line"><span class="comment"># 对合并生成的新节点,做一个标签</span></span><br><span class="line">git tag -a 1.2</span><br><span class="line"></span><br><span class="line"><span class="comment"># 再合并到develop分支</span></span><br><span class="line">git checkout develop</span><br><span class="line">git merge --no-ff release-x</span><br><span class="line"></span><br><span class="line"><span class="comment"># 最后,删除预发布分支</span></span><br><span class="line">git branch -d release-x</span><br></pre></td></tr></table></figure></p><h4 id="bug修补分支"><a href="#bug修补分支" class="headerlink" title="bug修补分支"></a>bug修补分支</h4><p>软件正式发布以后,难免会出现bug。这时就需要创建一个分支,进行bug修补。</p><p>修补bug分支是从Master分支上面分出来的。修补结束以后,再合并进master和develop分支。它的命名,可以采用hotfix-x的形式。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建一个修补bug分支</span></span><br><span class="line">git checkout -b hotfix-x master</span><br><span class="line"></span><br><span class="line"><span class="comment"># 修补结束后,合并到master分支</span></span><br><span class="line">git checkout master</span><br><span class="line">git merge --no-ff hotfix-x</span><br><span class="line">git tag -a 0.1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 再合并到develop分支</span></span><br><span class="line">git checkout develop</span><br><span class="line">git merge --no-ff hotfix-x</span><br><span class="line"></span><br><span class="line"><span class="comment"># 删除"修补bug分支"</span></span><br><span class="line">git branch -d hotfix-x</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/20191010172919306.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTUyMjQ0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>上面许多指令使用的–no-ff的意思是no-fast-farward的缩写,使用该命令可以保持更多的版本演进的细节。如果不使用该参数,默认使用了fast-farword进行merge。两者的区别如下图所示:<br><img src="https://img-blog.csdnimg.cn/2019101017424529.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTUyMjQ0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p>最后分享一下整体的分支管理策略图示:<br><img src="https://img-blog.csdnimg.cn/20191010174810996.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTUyMjQ0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p>参考:</p><blockquote><p><a href="https://nvie.com/posts/a-successful-git->branching-model/" target="_blank" rel="noopener">A successful Git branching model</a><br>—from <a href="https://nvie.com/about/" target="_blank" rel="noopener">Vincent Driessen</a></p></blockquote><hr>]]></content>
<summary type="html">
<p>前几天整理了一下之前项目的开发代码,当时使用了Git来进行代码管理。虽然本人熟悉常用的Git操作,但是对分支的管理经验非常欠缺。拿这个项目来说,在项目中有不下20个分支,每个分支间的继承关系相当之混乱,非常不利于代码的安全管理。因此,通过在网络上的学习,总结了一下关于Git分支管理的策略方法,供后续回顾学习。</p>
<p>当然必须承认,代码分支管理策略有很多种,不局限于以下介绍。但是下面介绍的这个分支管理策略非常具有工程借鉴意义,几乎适用于所有开发场景。</p>
<table>
<thead>
<tr>
<th style="text-align:center">分支</th>
<th style="text-align:center">命名</th>
<th style="text-align:center">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">主分支</td>
<td style="text-align:center">master</td>
<td style="text-align:center">主分支,所有提供给用户使用的正式版本,都在这个主分支上发布</td>
</tr>
<tr>
<td style="text-align:center">开发分支</td>
<td style="text-align:center">develop</td>
<td style="text-align:center">开发分支,永远是功能最新最全的分支</td>
</tr>
<tr>
<td style="text-align:center">功能分支</td>
<td style="text-align:center">feature-*</td>
<td style="text-align:center">新功能分支,某个功能点正在开发阶段</td>
</tr>
<tr>
<td style="text-align:center">发布版本</td>
<td style="text-align:center">release-*</td>
<td style="text-align:center">发布定期要上线的功能</td>
</tr>
<tr>
<td style="text-align:center">修复分支</td>
<td style="text-align:center">hotfix-*</td>
<td style="text-align:center">修复线上代码的 bug</td>
</tr>
</tbody>
</table>
</summary>
<category term="Git" scheme="http://kunxiang.wang/categories/Git/"/>
<category term="Git" scheme="http://kunxiang.wang/tags/Git/"/>
</entry>
<entry>
<title>浅析Python中的列表和元组</title>
<link href="http://kunxiang.wang/2019/10/07/%E6%B5%85%E6%9E%90Python%E4%B8%AD%E7%9A%84%E5%88%97%E8%A1%A8%E5%92%8C%E5%85%83%E7%BB%84/"/>
<id>http://kunxiang.wang/2019/10/07/浅析Python中的列表和元组/</id>
<published>2019-10-07T05:25:10.000Z</published>
<updated>2019-10-07T05:26:09.102Z</updated>
<content type="html"><![CDATA[<h4 id="区别"><a href="#区别" class="headerlink" title="区别"></a>区别</h4><ol><li>列表是<code>动态数组</code>,它们可变且可以重设长度(改变其内部元素的个数)。</li><li>元组是<code>静态数组</code>,它们不可变,且其内部数据一旦创建便无法改变。</li><li>元组缓存于Python运行时环境,这意味着我们每次使用元组时无须访问内核去 分配内存。</li></ol><p>这些区别揭示了两者在设计哲学上的不同:元组用于描述一个不会改变的事物的多个属性,而列表可被用于保存多个互相独立对象的数据集合。</p><a id="more"></a><h4 id="动态数组–列表"><a href="#动态数组–列表" class="headerlink" title="动态数组–列表"></a>动态数组–列表</h4><p>列表可以改变大小及内容不同,列表的可变性的代价在于存储它们需要额外的内存以及使用它们需要额外的计算。我们在<a href="https://mp.weixin.qq.com/s?__biz=MzU5OTUwMTA4NA==&mid=2247483804&idx=1&sn=4cef9561e71e5c6a621529be757a5b2f&chksm=feb2b1efc9c538f9ddcb91175fedd6468cfbc5e2b613b3d8a48077a8ea0194b41a7ff8e20e9d&token=475883438&lang=zh_CN#rd" target="_blank" rel="noopener">浅析Python中列表操作之*和*=</a>中一起研究了cpython的list对象的源码,看到了list对象的动态分配数组的大体过程(调用resize函数),而且在动态调整数组大小时使用如下的分配公式:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">new_allocated = (<span class="keyword">size_t</span>)newsize + (newsize >> <span class="number">3</span>) + (newsize < <span class="number">9</span> ? <span class="number">3</span> : <span class="number">6</span>);</span><br></pre></td></tr></table></figure><p>下图是一个列表多次添加元素时分配空间的变化示意图:</p><p><img src="https://img-blog.csdnimg.cn/20191007131224310.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTUyMjQ0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><h4 id="静态数组–元组"><a href="#静态数组–元组" class="headerlink" title="静态数组–元组"></a>静态数组–元组</h4><p>元组的不可改变性使其成为了一个非常轻量级的数据结构。这意味着存储元组不需要很多的内存开销,而且对元组的操作也非常直观。一旦元组被创建,它的内容无法被修改或它的大小也无法被改变。虽然它们不支持改变大小,但是我们可以将两个元组合并成一个新元组。这一操作类似列表的resize操作,但我们不需要为新生成的元组分配任何<code>额外</code>的空间。任意两个元组相加或者元组乘以一个整数进行repeat始终返回一个新分配的元组。其中两个元组相加调用cpython中的tupleconcat方法,而乘法操作调用的是tuplerepeat方法。上述两个方法的实现如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> PyObject *</span><br><span class="line">tupleconcat(PyTupleObject *a, PyObject *bb)</span><br><span class="line">{</span><br><span class="line"> ...</span><br><span class="line"> size = Py_SIZE(a) + Py_SIZE(b);</span><br><span class="line"> np = tuple_alloc(size);</span><br><span class="line"> ...</span><br><span class="line"> <span class="keyword">return</span> (PyObject *)np;</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> PyObject *</span><br><span class="line">tuplerepeat(PyTupleObject *a, Py_ssize_t n)</span><br><span class="line">{</span><br><span class="line"> ...</span><br><span class="line"> size = Py_SIZE(a) * n;</span><br><span class="line"> np = tuple_alloc(size);</span><br><span class="line"> ...</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (PyObject *) np;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>元组的静态特性的另一个好处体现在一些会在Python后台发生的事:资源缓存。Python是一门垃圾收集语言,这意味着当一个变量不再被使用时,Python会将该变量使用的内存释放回操作系统,以供其他程序(或变量)使用。<code>然而,从源码中可以看到,对于长度为1~20的元组,即使它们不再被使用,它们的空间也不会立刻被还给系统,而是留待未来使用</code>。这意味着当未来需要一个同样大小的新元组时,我们不再需要向操作系统申请一块内存来存放数据,因为我们已经有了预留的内存。</p><p><img src="https://img-blog.csdnimg.cn/20191007131407450.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTUyMjQ0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><p>我们可以验证资源缓存这一点,可以看到初始化一个列表消耗的时间是初始化一个元组消耗时间的6倍!可以想象一下,某些场景中在一个循环中频繁创建列表,耗时还是非常可观的,此时可以考虑使用元组来提高执行效率。<br><img src="https://img-blog.csdnimg.cn/20191007132116239.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTUyMjQ0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><hr>]]></content>
<summary type="html">
<h4 id="区别"><a href="#区别" class="headerlink" title="区别"></a>区别</h4><ol>
<li>列表是<code>动态数组</code>,它们可变且可以重设长度(改变其内部元素的个数)。</li>
<li>元组是<code>静态数组</code>,它们不可变,且其内部数据一旦创建便无法改变。</li>
<li>元组缓存于Python运行时环境,这意味着我们每次使用元组时无须访问内核去 分配内存。</li>
</ol>
<p>这些区别揭示了两者在设计哲学上的不同:元组用于描述一个不会改变的事物的多个属性,而列表可被用于保存多个互相独立对象的数据集合。</p>
</summary>
<category term="Python3 进阶" scheme="http://kunxiang.wang/categories/Python3-%E8%BF%9B%E9%98%B6/"/>
<category term="Python3" scheme="http://kunxiang.wang/tags/Python3/"/>
<category term="Python源码" scheme="http://kunxiang.wang/tags/Python%E6%BA%90%E7%A0%81/"/>
</entry>
<entry>
<title>浅析Python中列表操作之*和*=</title>
<link href="http://kunxiang.wang/2019/10/07/%E6%B5%85%E6%9E%90Python%E4%B8%AD%E5%88%97%E8%A1%A8%E6%93%8D%E4%BD%9C%E4%B9%8B-%E5%92%8C/"/>
<id>http://kunxiang.wang/2019/10/07/浅析Python中列表操作之-和/</id>
<published>2019-10-06T16:42:03.000Z</published>
<updated>2019-10-07T05:33:14.349Z</updated>
<content type="html"><![CDATA[<p>初学Python时总是会将a*=n理解为a=a*n,稍微深入后就会知道在Python中的不同,其中<em>调用<strong>mul</strong> ,而</em>=调用<strong>imul</strong> 。</p><p>对于list对象也支持乘法操作,截止到Python3.7版本,上述仍然是成立的。我们知道list是由C实现的,所以真正的底层调用肯定是C的实现。观察list对象的C实现的源码我们会知道乘法*操作调用list_repeat,*=会调用list_inplace_repeat,下面分别看一下两者的C实现方式。</p><h3 id="▍-–-gt-list-repeat"><a href="#▍-–-gt-list-repeat" class="headerlink" title="▍* –> list_repeat"></a>▍* –> list_repeat</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> PyObject *</span><br><span class="line">list_repeat(PyListObject *a, Py_ssize_t n)</span><br><span class="line">{</span><br><span class="line"> ...</span><br><span class="line"> size = Py_SIZE(a) * n;</span><br><span class="line"> <span class="keyword">if</span> (size == <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> PyList_New(<span class="number">0</span>);</span><br><span class="line"> np = (PyListObject *) list_new_prealloc(size);</span><br><span class="line"> ...</span><br><span class="line"> <span class="keyword">return</span> (PyObject *) np;</span><br><span class="line">}</span><br><span class="line">从以上可以看出,list_repeat方法需要多少空间就申请多少空间,该操作返回的一个新的列表对象。</span><br></pre></td></tr></table></figure><h3 id="▍-–-gt-list-inplace-repeat"><a href="#▍-–-gt-list-inplace-repeat" class="headerlink" title="▍*= –> list_inplace_repeat"></a>▍*= –> list_inplace_repeat</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> PyObject *</span><br><span class="line">list_inplace_repeat(PyListObject *self, Py_ssize_t n)</span><br><span class="line">{</span><br><span class="line"> ...</span><br><span class="line"> size = PyList_GET_SIZE(self);</span><br><span class="line"> <span class="keyword">if</span> (list_resize(self, size*n) < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> ...</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">int</span></span><br><span class="line">list_resize(PyListObject *self, Py_ssize_t newsize)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (allocated >= newsize && newsize >= (allocated >> <span class="number">1</span>)) {</span><br><span class="line"> assert(self->ob_item != <span class="literal">NULL</span> || newsize == <span class="number">0</span>);</span><br><span class="line"> Py_SIZE(self) = newsize;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> ...</span><br><span class="line"> new_allocated = (<span class="keyword">size_t</span>)newsize + (newsize >> <span class="number">3</span>) + (newsize < <span class="number">9</span> ? <span class="number">3</span> : <span class="number">6</span>);</span><br><span class="line"> ...</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>list_inplace_repeat代码中通过调用list_resize来进行扩容,并告诉它这个列表需要容纳size*n个元素。从list_resize代码来看,当allocated空间足够时,不会进行扩容操作。但是新申请的空间总是比所需要的大的。如果进行pop等减小list元素数量的操作来看,实际上列表的大小也会按照相应策略进行缩减操作。</p><blockquote><p>If the newsize falls lower than half the allocated size, then proceed with the realloc() to shrink the list. — From cpython</p></blockquote><h3 id="▍总结"><a href="#▍总结" class="headerlink" title="▍总结"></a>▍总结</h3><ol><li>*=会调用list_resize,可能会引起list空间扩容的情况,而且此时list对象占用空间会比实际list对象中元素占用空间大。</li><li>*会按需获取申请空间大小,不会调用list_resize方法。</li></ol>]]></content>
<summary type="html">
<p>初学Python时总是会将a*=n理解为a=a*n,稍微深入后就会知道在Python中的不同,其中<em>调用<strong>mul</strong> ,而</em>=调用<strong>imul</strong> 。</p>
<p>对于list对象也支持乘法操作,截止到P
</summary>
<category term="Python3 进阶" scheme="http://kunxiang.wang/categories/Python3-%E8%BF%9B%E9%98%B6/"/>
<category term="Python3" scheme="http://kunxiang.wang/tags/Python3/"/>
<category term="Python源码" scheme="http://kunxiang.wang/tags/Python%E6%BA%90%E7%A0%81/"/>
</entry>
<entry>
<title>神经网络的学习为何要设定损失函数?</title>
<link href="http://kunxiang.wang/2019/10/01/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E7%9A%84%E5%AD%A6%E4%B9%A0%E4%B8%BA%E4%BD%95%E8%A6%81%E8%AE%BE%E5%AE%9A%E6%8D%9F%E5%A4%B1%E5%87%BD%E6%95%B0%EF%BC%9F/"/>
<id>http://kunxiang.wang/2019/10/01/神经网络的学习为何要设定损失函数?/</id>
<published>2019-09-30T16:17:38.000Z</published>
<updated>2019-09-30T16:47:28.497Z</updated>
<content type="html"><![CDATA[<p>这里所说的“学习”是指从训练数据中<strong>自动</strong>获取最优权重参数的过程。学习的目的就是以该损失函数为基准,找出能使它的值达到最小的权重参数。</p><p>可能会有人问:我们想获得的是能提高识别精度的参数,特意再导入一个损失函数不是有些重复劳动吗?既然我们的目标是获得使识别精度尽可能高的神经网络,那不是应该把识别精度作为指标吗?</p><a id="more"></a><p>听起来很有道理!</p><p>对于这一疑问,我们可以根据<strong>“导数“</strong>在神经网络学习中的作用来回答。 在神经网络的学习中,寻找最优参数(权重和偏置)时, 要寻找使损失函数的值尽可能小的参数。为了找到使损失函数的值尽可能小 的地方,需要计算参数的导数(确切地讲是梯度),然后以这个导数为指引, 逐步更新参数的值。</p><p>假设有一个神经网络,现在我们来关注这个神经网络中的某一个权重参数。此时,对该权重参数的损失函数求导,此处导数的含义可以理解为“如果稍微改变这个权重参数的值,损失函数的值会如何变化”。<strong>如果导数的值为负,通过使该权重参数向正方向改变,可以减小损失函数的值;反过来,如果导数的值为正, 则通过使该权重参数向负方向改变,可以减小损失函数的值</strong>。不过,当导数为 0 时,无论权重参数向哪个方向变化,损失函数的值都不会改变,此时该权重参数的更新会停在此处。</p><p><strong>在进行神经网络的学习时,不能将识别精度作为指标。因为如果以识别精度为指标,则参数的导数在绝大多数地方都会变为 0,导致参数无法更新。</strong>那为什么用识别精度作为指标时,参数的导数在绝大多数地方都会变成0呢?</p><p>为了回答这个问题,我们来思考另一个具体例子。假设某个神经网络正确识别出了 100个训练数据中的32笔,此时识别精度为 32 %。如果以识别精度为指标,即使稍微改变权重参数的值,识别精度也仍将保持在 32 %,不会出现变化。也就是说,仅仅微调参数,是无法改善识别精度的。即便识别精度有所改善,它的值也不会像 32.0123 . . . % 这样连续变化,而是变为 33 %、 34 % 这样的<strong>不连续的、离散的值</strong>。而如果把损失函数作为指标,则当前损失函数的值可以表示为 0.92543 . . . 这样的值。并且,如果稍微改变一下参数 的值,对应的损失函数也会像 0.93432 . . . 这样发生连续性的变化。</p><p>作为激活函数的阶跃函数也有同样的情况。出于相同的原因,如果使用阶跃函数作为激活函数,神经网络的学习将无法进行。原因是阶跃函数的导数在绝大多数地方(除了0以外的地方)均为0。 也就是说,如果使用了阶跃函数,那么即便将损失函数作为指标,参数的微小变化也会被阶跃函数<strong>抹杀</strong>,导致损失函数的值不会产生任何变化。</p><p>而 sigmoid 函数,不仅函数的输出(竖轴的值)是连续变化的,曲线的斜率(导数) 也是连续变化的。也就是说,sigmoid 函数的导数在任何地方都不为 0。这对神经网络的学习非常重要。得益于这个斜率不会为 0 的性质,神经网络的学习得以正确进行。</p><p><img src="https://img-blog.csdnimg.cn/20191001001019693.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTUyMjQ0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述">—-<br>参考数据<br>深度学习入门-Deep Learning from Scratch</p>]]></content>
<summary type="html">
<p>这里所说的“学习”是指从训练数据中<strong>自动</strong>获取最优权重参数的过程。学习的目的就是以该损失函数为基准,找出能使它的值达到最小的权重参数。</p>
<p>可能会有人问:我们想获得的是能提高识别精度的参数,特意再导入一个损失函数不是有些重复劳动吗?既然我们的目标是获得使识别精度尽可能高的神经网络,那不是应该把识别精度作为指标吗?</p>
</summary>
<category term="机器学习" scheme="http://kunxiang.wang/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="机器学习" scheme="http://kunxiang.wang/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="神经网络" scheme="http://kunxiang.wang/tags/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/"/>
</entry>
<entry>
<title>神经网络的激活函数为什么要使用非线性函数</title>
<link href="http://kunxiang.wang/2019/09/29/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E7%9A%84%E6%BF%80%E6%B4%BB%E5%87%BD%E6%95%B0%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E4%BD%BF%E7%94%A8%E9%9D%9E%E7%BA%BF%E6%80%A7%E5%87%BD%E6%95%B0/"/>
<id>http://kunxiang.wang/2019/09/29/神经网络的激活函数为什么要使用非线性函数/</id>
<published>2019-09-29T02:58:43.000Z</published>
<updated>2019-09-29T03:02:35.783Z</updated>
<content type="html"><![CDATA[<h3 id="▍什么是激活函数"><a href="#▍什么是激活函数" class="headerlink" title="▍什么是激活函数"></a>▍什么是激活函数</h3><p>在神经元中,输入的inputs通过加权求和,然后被作用了一个函数,这个函数就是激活函数 <code>Activation Function</code>。激活函数在神经网络中的位置如图所示:<br><img src="https://img-blog.csdnimg.cn/20190908231352415.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTUyMjQ0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p><a id="more"></a><h3 id="▍为什么要用非线性函数"><a href="#▍为什么要用非线性函数" class="headerlink" title="▍为什么要用非线性函数"></a>▍为什么要用非线性函数</h3><p>要解释这个问题,可以反过来思考一下,<code>为什么激活函数不能使用线性函数</code>。<br>如果使用线性函数,每一层输出都是上层输入的线性函数,无论神经网络有多少层,输出都是输入的<code>线性组合</code>。加深神经网络的层数就没有什么意义了。线性函数的问题在于不管加深层数到多少,总是存在与之等效的<code>「无隐藏层」</code>的神经网络。为了稍微直观的理解这一点,考虑下面一个简单的例子。</p><p>存在一个线性函数<code>f(x)=kx(k≠0)</code>作为激活函数,将<code>y=f(f(f(x)))</code>对应三层的神经网络。很明显可以想到同样的处理可以由<code>y=ax(a=k^3)</code>,一个没有隐藏层的神经网络来表示。该例子仅仅是一个近似,实际中的神经网络的运算要比这个例子复杂很多,但不影响结论的成立。也就是说,使用线性激活函数时,无法发挥多层网络带来的优势。</p><p>相反如果使用非线性函数,激活函数给神经元引入了非线性因素,使得神经网络可以任意逼近任何非线性函数,这样神经网络就可以应用到众多的非线性模型中。</p><p>以上!</p>]]></content>
<summary type="html">
<h3 id="▍什么是激活函数"><a href="#▍什么是激活函数" class="headerlink" title="▍什么是激活函数"></a>▍什么是激活函数</h3><p>在神经元中,输入的inputs通过加权求和,然后被作用了一个函数,这个函数就是激活函数 <code>Activation Function</code>。激活函数在神经网络中的位置如图所示:<br><img src="https://img-blog.csdnimg.cn/20190908231352415.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTUyMjQ0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
</summary>
<category term="机器学习" scheme="http://kunxiang.wang/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="机器学习" scheme="http://kunxiang.wang/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
<category term="神经网络" scheme="http://kunxiang.wang/tags/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/"/>
</entry>
<entry>
<title>服务器中的物理CPU、逻辑CPU和CPU核数</title>
<link href="http://kunxiang.wang/2019/06/20/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%AD%E7%9A%84%E7%89%A9%E7%90%86CPU%E3%80%81%E9%80%BB%E8%BE%91CPU%E5%92%8CCPU%E6%A0%B8%E6%95%B0/"/>
<id>http://kunxiang.wang/2019/06/20/服务器中的物理CPU、逻辑CPU和CPU核数/</id>
<published>2019-06-20T14:18:07.000Z</published>
<updated>2019-06-23T14:23:08.731Z</updated>
<content type="html"><![CDATA[<h2 id="重要概念"><a href="#重要概念" class="headerlink" title="重要概念"></a>重要概念</h2><h3 id="物理CPU"><a href="#物理CPU" class="headerlink" title="物理CPU"></a>物理CPU</h3><p>实际Server中插槽上的CPU个数<br>物理cpu数量,可以数不重复的 physical id 有几个,查看方法</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">grep <span class="string">"physical id"</span> /proc/cpuinfo|sort|uniq|wc -l</span><br><span class="line">2</span><br><span class="line">``` </span><br><span class="line"></span><br><span class="line"><span class="comment">### CPU核数 </span></span><br><span class="line">单块CPU上面能处理数据的芯片组的数量,如双核、四核等 (cpu cores)。</span><br><span class="line">比如现在的i5 760,是双核心四线程的CPU、而 i5 2250 是四核心四线程的CPU 。一般来说,物理CPU个数×每颗核数就应该等于逻辑CPU的个数,如果不相等的话,则表示服务器的CPU支持超线程技术 </span><br><span class="line"></span><br><span class="line">```bash</span><br><span class="line">cat /proc/cpuinfo |grep <span class="string">"cpu cores"</span>|uniq</span><br><span class="line">grep <span class="string">"cpu cores"</span> /proc/cpuinfo|uniq|awk -F <span class="string">":"</span> <span class="string">"{print <span class="variable">$2</span>}"</span></span><br><span class="line">8</span><br></pre></td></tr></table></figure><h3 id="逻辑CPU"><a href="#逻辑CPU" class="headerlink" title="逻辑CPU"></a>逻辑CPU</h3><p>Linux用户对 /proc/cpuinfo 这个文件肯定不陌生. 它是用来存储cpu硬件信息的<br>信息内容分别列出了processor 0 – n 的规格。这里需要注意,如果你认为n就是真实的cpu数的话, 就大错特错了。</p><p>一般情况,我们认为<code>一颗cpu可以有多核</code>,加上<code>intel的超线程技术(HT)</code>, 可以在逻辑上再分一倍数量的cpu core出来<br><code>逻辑CPU数量=物理cpu数量 x cpu cores 这个规格值 x 2(如果支持并开启ht)</code>。</p><p><code>如果有一个以上逻辑处理器拥有相同的 core id 和 physical id,则说明系统支持超线程(HT)技术</code></p><p>备注一下:Linux下top查看的CPU也是逻辑CPU个数</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cat /proc/cpuinfo| grep <span class="string">"processor"</span> |wc -l</span><br><span class="line">32(支持超线程)</span><br></pre></td></tr></table></figure><a id="more"></a><h2 id="查看方法"><a href="#查看方法" class="headerlink" title="查看方法"></a>查看方法</h2><p>通过cat /proc/cpuinfocpu来查看相关信息。</p><blockquote><ul><li>vendor id 如果处理器为英特尔处理器,则字符串是 GenuineIntel。</li><li>processor 包括这一逻辑处理器的唯一标识符。</li><li>physical id 包括每个物理封装的唯一标识符。</li><li>core id 保存每个内核的唯一标识符。</li><li>siblings 列出了位于相同物理封装中的逻辑处理器的数量。</li><li>cpu cores 包含位于相同物理封装中的内核数量。</li></ul></blockquote><ol><li>拥有相同 physical id 的所有逻辑处理器共享同一个物理插座,每个 physical id 代表一个唯一的物理封装。</li><li>Siblings 表示位于这一物理封装上的逻辑处理器的数量,它们可能支持也可能不支持超线程(HT)技术。</li><li>每个 core id 均代表一个唯一的处理器内核,所有带有相同 core id 的逻辑处理器均位于同一个处理器内核上。简单的说:“siblings”指的是一个物理CPU有几个逻辑CPU,”cpu cores“指的是一个物理CPU有几个核。</li><li>如果有一个以上逻辑处理器拥有相同的 core id 和 physical id,则说明系统支持超线程(HT)技术。</li><li>如果有两个或两个以上的逻辑处理器拥有相同的 physical id,但是 core id不同,则说明这是一个多内核处理器。cpu cores条目也可以表示是否支持多内核。</li></ol><h2 id="top命令关于cpu使用率"><a href="#top命令关于cpu使用率" class="headerlink" title="top命令关于cpu使用率"></a>top命令关于cpu使用率</h2><p>下面做一个简单的测试,终端中使用如下命令<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">md5sum /dev/zero &</span><br></pre></td></tr></table></figure></p><p>开启top,如下所示</p><p><img src="https://upload-images.jianshu.io/upload_images/2952111-81c2a7654f73c645.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="Screen Shot 2019-06-20 at 22.53.34.png"></p><p>按数字键1后查看所有核的使用率。</p><p><img src="https://upload-images.jianshu.io/upload_images/2952111-70b5f8c2b58f77cd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="Screen Shot 2019-06-20 at 22.56.42.png"></p><p>发现使用top命令,左上角显示的是整体负载,即单核的负载数除以核数。%CPU数值代表单个核的使用率,超过100%代表使用其他核的计算资源。</p><p>第一行:</p><ul><li>10:01:23 — 当前系统时间</li><li>126 days, 14:29 — 系统已经运行了126天14小时29分钟(在这期间没有重启过)</li><li>2 users — 当前有2个用户登录系统</li><li>load average: 1.15, 1.42, 1.44 — load average后面的三个数分别是1分钟、5分钟、15分钟的负载情况。load average数据是每隔5秒钟检查一次活跃的进程数,然后按特定算法计算出的数值。如果这个数<code>除以逻辑CPU的数量</code>,<code>结果高于5的时候就表明系统在超负荷运转了。</code></li></ul><p>第二行:</p><ul><li>Tasks — 任务(进程),系统现在共有183个进程,其中处于运行中的有1个,182个在休眠(sleep),stoped状态的有0个,zombie状态(僵尸)的有0个。</li></ul><p>第三行:cpu状态</p><ul><li>6.7% us — 用户空间占用CPU的百分比。</li><li>0.4% sy — 内核空间占用CPU的百分比。</li><li>0.0% ni — 改变过优先级的进程占用CPU的百分比</li><li>92.9% id — 空闲CPU百分比</li><li>0.0% wa — IO等待占用CPU的百分比</li><li>0.0% hi — 硬中断(Hardware IRQ)占用CPU的百分比</li><li>0.0% si — 软中断(Software Interrupts)占用CPU的百分比</li></ul><hr>]]></content>
<summary type="html">
<h2 id="重要概念"><a href="#重要概念" class="headerlink" title="重要概念"></a>重要概念</h2><h3 id="物理CPU"><a href="#物理CPU" class="headerlink" title="物理CPU"></a>物理CPU</h3><p>实际Server中插槽上的CPU个数<br>物理cpu数量,可以数不重复的 physical id 有几个,查看方法</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">grep <span class="string">"physical id"</span> /proc/cpuinfo|sort|uniq|wc -l</span><br><span class="line">2</span><br><span class="line">``` </span><br><span class="line"></span><br><span class="line"><span class="comment">### CPU核数 </span></span><br><span class="line">单块CPU上面能处理数据的芯片组的数量,如双核、四核等 (cpu cores)。</span><br><span class="line">比如现在的i5 760,是双核心四线程的CPU、而 i5 2250 是四核心四线程的CPU 。一般来说,物理CPU个数×每颗核数就应该等于逻辑CPU的个数,如果不相等的话,则表示服务器的CPU支持超线程技术 </span><br><span class="line"></span><br><span class="line">```bash</span><br><span class="line">cat /proc/cpuinfo |grep <span class="string">"cpu cores"</span>|uniq</span><br><span class="line">grep <span class="string">"cpu cores"</span> /proc/cpuinfo|uniq|awk -F <span class="string">":"</span> <span class="string">"&#123;print <span class="variable">$2</span>&#125;"</span></span><br><span class="line">8</span><br></pre></td></tr></table></figure>
<h3 id="逻辑CPU"><a href="#逻辑CPU" class="headerlink" title="逻辑CPU"></a>逻辑CPU</h3><p>Linux用户对 /proc/cpuinfo 这个文件肯定不陌生. 它是用来存储cpu硬件信息的<br>信息内容分别列出了processor 0 – n 的规格。这里需要注意,如果你认为n就是真实的cpu数的话, 就大错特错了。</p>
<p>一般情况,我们认为<code>一颗cpu可以有多核</code>,加上<code>intel的超线程技术(HT)</code>, 可以在逻辑上再分一倍数量的cpu core出来<br><code>逻辑CPU数量=物理cpu数量 x cpu cores 这个规格值 x 2(如果支持并开启ht)</code>。</p>
<p><code>如果有一个以上逻辑处理器拥有相同的 core id 和 physical id,则说明系统支持超线程(HT)技术</code></p>
<p>备注一下:Linux下top查看的CPU也是逻辑CPU个数</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cat /proc/cpuinfo| grep <span class="string">"processor"</span> |wc -l</span><br><span class="line">32(支持超线程)</span><br></pre></td></tr></table></figure>
</summary>
<category term="操作系统" scheme="http://kunxiang.wang/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
<category term="操作系统" scheme="http://kunxiang.wang/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
</entry>
<entry>
<title>Linux查看端口占用情况</title>
<link href="http://kunxiang.wang/2019/05/28/Linux%E6%9F%A5%E7%9C%8B%E7%AB%AF%E5%8F%A3%E5%8D%A0%E7%94%A8%E6%83%85%E5%86%B5/"/>
<id>http://kunxiang.wang/2019/05/28/Linux查看端口占用情况/</id>
<published>2019-05-28T02:11:18.000Z</published>
<updated>2019-05-28T05:53:41.246Z</updated>
<content type="html"><![CDATA[<h3 id="lsof"><a href="#lsof" class="headerlink" title="lsof"></a>lsof</h3><ul><li><p>lsof -i 用以显示符合条件的进程情况,lsof(list open files)是一个列出当前系统打开文件的工具。以root用户来执行lsof -i命令</p></li><li><p>lsof -i:端口号,用于查看某一端口的占用情况,比如查看22号端口使用情况,lsof -i:22</p></li></ul><p><img src="https://upload-images.jianshu.io/upload_images/2952111-34cfaa89c8a414a5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="Screen Shot 2019-05-28 at 13.50.08.png"></p><h3 id="netstat"><a href="#netstat" class="headerlink" title="netstat"></a>netstat</h3><p>netstat -tunlp用于显示tcp,udp的端口和进程等相关情况</p><p><img src="https://upload-images.jianshu.io/upload_images/2952111-79a5c99ebc5ba5c3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="Screen Shot 2019-05-28 at 13.51.26.png"></p>]]></content>
<summary type="html">
<h3 id="lsof"><a href="#lsof" class="headerlink" title="lsof"></a>lsof</h3><ul>
<li><p>lsof -i 用以显示符合条件的进程情况,lsof(list open files)是一个列出当前系统打
</summary>
<category term="Linux/Mac OS" scheme="http://kunxiang.wang/categories/Linux-Mac-OS/"/>
<category term="Linux/Mac OS" scheme="http://kunxiang.wang/tags/Linux-Mac-OS/"/>
</entry>
<entry>
<title>Java实时读取log日志文件示例代码</title>
<link href="http://kunxiang.wang/2019/05/21/Java%E5%AE%9E%E6%97%B6%E8%AF%BB%E5%8F%96log%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81/"/>
<id>http://kunxiang.wang/2019/05/21/Java实时读取log日志文件示例代码/</id>
<published>2019-05-21T06:28:14.000Z</published>
<updated>2019-11-26T02:01:26.640Z</updated>
<content type="html"><![CDATA[<p><code>需求</code>:正在开发一个监控系统,要求将多台日志信息实时采集出来,然后保存到Kafka中,后期对日志数据进行spark运算、大数据处理分析,日志按大小,时间切分。</p><p><code>运用的技术</code>:RandomAccessFile类中seek方法可以从指定位置读取文件,可以用来实现文件实时读取,JDK文档有对RandomAccessFile的介绍。</p><p><code>思想</code>:在每一次读取后,close一下就不会影响重命名操作了。因为日志是线上机器产生的,我们只需要写实时读取的方法即可,但是这里为了模拟实际情况,也把产生日志的方法出来,在测试的时候,可以手动改变日志的名称,更为方便的处理方式—–将日志mock.log直接删除即可。</p><p><code>原生RandomAccessFile效率较低,后面附有BufferedRandomAccessFile</code></p><p>模拟写日志的类<br>因为日志是按大小和时间切分的,在测试的时候,直接修改日志的名称,或者删除日志。<br><a id="more"></a></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.inveno.file;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.File;</span><br><span class="line"><span class="keyword">import</span> java.io.FileWriter;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.Writer;</span><br><span class="line"><span class="keyword">import</span> java.text.SimpleDateFormat;</span><br><span class="line"><span class="keyword">import</span> java.util.Date;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.Executors;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ScheduledExecutorService;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.slf4j.Logger;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.LoggerFactory;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LogSvr</span> </span>{</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Logger logger = LoggerFactory.getLogger(LogSvr.class);</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> SimpleDateFormat dateFormat = <span class="keyword">new</span> SimpleDateFormat(<span class="string">"yyy-MM-dd HH:mm:ss"</span>);</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> ScheduledExecutorService exec = Executors.newScheduledThreadPool(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">logMsg</span><span class="params">(File logFile,String msgInfo)</span> <span class="keyword">throws</span> IOException</span>{</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(!logFile.exists()) {</span><br><span class="line">logFile.createNewFile();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">Writer txtWriter = <span class="keyword">new</span> FileWriter(logFile,<span class="keyword">true</span>);</span><br><span class="line">txtWriter.write(dateFormat.format(<span class="keyword">new</span> Date()) + <span class="string">"\t"</span> + msgInfo + <span class="string">"\n"</span>);</span><br><span class="line">txtWriter.flush();</span><br><span class="line">txtWriter.close();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">stop</span><span class="params">()</span></span>{</span><br><span class="line"><span class="keyword">if</span>(exec != <span class="keyword">null</span>){</span><br><span class="line">exec.shutdown();</span><br><span class="line">logger.info(<span class="string">"file write stop !"</span>);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"></span><br><span class="line"><span class="keyword">final</span> LogSvr logSvr = <span class="keyword">new</span> LogSvr();</span><br><span class="line"><span class="keyword">final</span> File tmpLogFile = <span class="keyword">new</span> File(<span class="string">"pathtolog.log"</span>);</span><br><span class="line"><span class="keyword">final</span> String msgInfo = <span class="string">"test !"</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//启动一个线程每5秒向日志文件写一次数据</span></span><br><span class="line">exec.scheduleWithFixedDelay(<span class="keyword">new</span> Runnable(){</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">try</span> {</span><br><span class="line">logSvr.logMsg(tmpLogFile, msgInfo);</span><br><span class="line"><span class="comment">//Thread.sleep(1000);</span></span><br><span class="line">} <span class="keyword">catch</span> (Exception e) {</span><br><span class="line">logger.error(<span class="string">"file write error !"</span>);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">}, <span class="number">0</span>, <span class="number">5</span>, TimeUnit.SECONDS);</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">```java</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.log4j.Logger;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.File;</span><br><span class="line"><span class="keyword">import</span> java.io.RandomAccessFile;</span><br><span class="line"><span class="keyword">import</span> java.text.SimpleDateFormat;</span><br><span class="line"><span class="keyword">import</span> java.util.Date;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.Executors;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ScheduledExecutorService;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LogView</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Logger logger = Logger.getLogger(Start.class.getName());</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">long</span> pointer = <span class="number">0</span>; <span class="comment">// 文件指针位置</span></span><br><span class="line"> <span class="keyword">private</span> SimpleDateFormat dateFormat = <span class="keyword">new</span> SimpleDateFormat(<span class="string">"yyy-MM-dd HH:mm:ss"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> ScheduledExecutorService exec = Executors.newScheduledThreadPool(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">realtimeShowLog</span><span class="params">(<span class="keyword">final</span> File logFile)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (logFile == <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">"logFile can not be null"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//启动一个线程每2秒读取新增的日志信息</span></span><br><span class="line"> exec.scheduleWithFixedDelay(<span class="keyword">new</span> Runnable() {</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获得变化部分</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">long</span> len = logFile.length();</span><br><span class="line"> <span class="keyword">if</span> (len < pointer) {</span><br><span class="line"> logger.info(<span class="string">"Log file was reset. Restarting logging from start of file."</span>);</span><br><span class="line"> pointer = <span class="number">0</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"></span><br><span class="line"> <span class="comment">//指定文件可读可写</span></span><br><span class="line"> RandomAccessFile randomFile = <span class="keyword">new</span> RandomAccessFile(logFile, <span class="string">"rw"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获取RandomAccessFile对象文件指针的位置,初始位置是0</span></span><br><span class="line"> logger.info(<span class="string">"RandomAccessFile文件指针的初始位置:"</span> + pointer);</span><br><span class="line"></span><br><span class="line"> randomFile.seek(pointer);<span class="comment">//移动到文件指针位置</span></span><br><span class="line"></span><br><span class="line"> String tmp;</span><br><span class="line"> <span class="keyword">while</span> ((tmp = randomFile.readLine()) != <span class="keyword">null</span>) {</span><br><span class="line"> System.out.println(<span class="string">"info : "</span> + <span class="keyword">new</span> String(tmp.getBytes(<span class="string">"utf-8"</span>)));</span><br><span class="line"> pointer = randomFile.getFilePointer();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> randomFile.close();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> <span class="comment">//实时读取日志异常,需要记录时间和lastTimeFileSize 以便后期手动补充</span></span><br><span class="line"> logger.error(dateFormat.format(<span class="keyword">new</span> Date()) + <span class="string">" File read error, pointer: "</span> + pointer);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="comment">//将pointer 落地以便下次启动的时候,直接从指定位置获取</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> }, <span class="number">0</span>, <span class="number">10</span>, TimeUnit.SECONDS);</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">stop</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (exec != <span class="keyword">null</span>) {</span><br><span class="line"> exec.shutdown();</span><br><span class="line"> logger.info(<span class="string">"file read stop !"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"></span><br><span class="line"> LogView view = <span class="keyword">new</span> LogView();</span><br><span class="line"> File tmpLogFile = <span class="keyword">new</span> File(<span class="string">"pathtolog.log"</span>);</span><br><span class="line"> System.out.println(tmpLogFile.getAbsolutePath());</span><br><span class="line"> view.pointer = <span class="number">0</span>;</span><br><span class="line"> view.realtimeShowLog(tmpLogFile);</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Licensed to the Apache Software Foundation (ASF) under one</span></span><br><span class="line"><span class="comment"> * or more contributor license agreements. See the NOTICE file</span></span><br><span class="line"><span class="comment"> * distributed with this work for additional information</span></span><br><span class="line"><span class="comment"> * regarding copyright ownership. The ASF licenses this file</span></span><br><span class="line"><span class="comment"> * to you under the Apache License, Version 2.0 (the</span></span><br><span class="line"><span class="comment"> * "License"); you may not use this file except in compliance</span></span><br><span class="line"><span class="comment"> * with the License. You may obtain a copy of the License at</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * http://www.apache.org/licenses/LICENSE-2.0</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></span><br><span class="line"><span class="comment"> * distributed under the License is distributed on an "AS IS" BASIS,</span></span><br><span class="line"><span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></span><br><span class="line"><span class="comment"> * See the License for the specific language governing permissions and</span></span><br><span class="line"><span class="comment"> * limitations under the License.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.File;</span><br><span class="line"><span class="keyword">import</span> java.io.FileNotFoundException;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.RandomAccessFile;</span><br><span class="line"><span class="keyword">import</span> java.util.Arrays;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * A <code>BufferedRandomAccessFile</code> is like a</span></span><br><span class="line"><span class="comment"> * <code>RandomAccessFile</code>, but it uses a private buffer so that most</span></span><br><span class="line"><span class="comment"> * operations do not require a disk access.</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * Note: The operations on this class are unmonitored. Also, the correct</span></span><br><span class="line"><span class="comment"> * functioning of the <code>RandomAccessFile</code> methods that are not</span></span><br><span class="line"><span class="comment"> * overridden here relies on the implementation of those methods in the</span></span><br><span class="line"><span class="comment"> * superclass.</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * To describe the above fields, we introduce the following abstractions for</span></span><br><span class="line"><span class="comment"> * the file "f":</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * len(f) the length of the file curr(f) the current position in the file</span></span><br><span class="line"><span class="comment"> * c(f) the abstract contents of the file disk(f) the contents of f's</span></span><br><span class="line"><span class="comment"> * backing disk file closed(f) true iff the file is closed</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * "curr(f)" is an index in the closed interval [0, len(f)]. "c(f)" is a</span></span><br><span class="line"><span class="comment"> * character sequence of length "len(f)". "c(f)" and "disk(f)" may differ if</span></span><br><span class="line"><span class="comment"> * "c(f)" contains unflushed writes not reflected in "disk(f)". The flush</span></span><br><span class="line"><span class="comment"> * operation has the effect of making "disk(f)" identical to "c(f)".</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * A file is said to be *valid* if the following conditions hold:</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * V1. The "closed" and "curr" fields are correct:</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * f.closed == closed(f) f.curr == curr(f)</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * V2. The current position is either contained in the buffer, or just past</span></span><br><span class="line"><span class="comment"> * the buffer:</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * f.lo <= f.curr <= f.hi</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * V3. Any (possibly) un-flushed characters are stored in "f.buff":</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * (forall i in [f.lo, f.curr): c(f)[i] == f.buff[i - f.lo])</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * V4. For all characters not covered by V3, c(f) and disk(f) agree:</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * (forall i in [f.lo, len(f)): i not in [f.lo, f.curr) => c(f)[i] ==</span></span><br><span class="line"><span class="comment"> * disk(f)[i])</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * V5. "f.dirty" is true iff the buffer contains bytes that should be</span></span><br><span class="line"><span class="comment"> * flushed to the file; by V3 and V4, only part of the buffer can be dirty.</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * f.dirty == (exists i in [f.lo, f.curr): c(f)[i] != f.buff[i - f.lo])</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * V6. this.maxHi == this.lo + this.buff.length</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * Note that "f.buff" can be "null" in a valid file, since the range of</span></span><br><span class="line"><span class="comment"> * characters in V3 is empty when "f.lo == f.curr".</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * A file is said to be *ready* if the buffer contains the current position,</span></span><br><span class="line"><span class="comment"> * i.e., when:</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * R1. !f.closed && f.buff != null && f.lo <= f.curr && f.curr < f.hi</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * When a file is ready, reading or writing a single byte can be performed</span></span><br><span class="line"><span class="comment"> * by reading or writing the in-memory buffer without performing a disk</span></span><br><span class="line"><span class="comment"> * operation.</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * !!!This class come from network ,I just adjust code style!!!</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhaofeng</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2018 -05-02</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">BufferedRandomAccessFile</span> <span class="keyword">extends</span> <span class="title">RandomAccessFile</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 64K buffer</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> LOG_BUFF_SZ = <span class="number">16</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> BUFF_SZ = (<span class="number">1</span> << LOG_BUFF_SZ);</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> BUFF_MASK = ~(((<span class="keyword">long</span>) BUFF_SZ) - <span class="number">1L</span>);</span><br><span class="line"> <span class="keyword">private</span> String path_;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * This implementation is based on the buffer implementation in Modula-3's</span></span><br><span class="line"><span class="comment"> * "Rd", "Wr", "RdClass", and "WrClass" interfaces.</span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * true iff un-flushed bytes exist</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">boolean</span> dirty_;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * dirty_ can be cleared by e.g. seek, so track sync separately</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">boolean</span> syncNeeded_;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * current position in file</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">long</span> curr_;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * bounds on characters in "buff"</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">long</span> lo_, hi_;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * local buffer</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">byte</span>[] buff_;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * this.lo + this.buff.length</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">long</span> maxHi_;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * buffer contains last file block?</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">boolean</span> hitEOF_;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * disk position</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">long</span> diskPos_;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Open a new <code>BufferedRandomAccessFile</code> on <code>file</code></span></span><br><span class="line"><span class="comment"> * in mode <code>mode</code>, which should be "r" for reading only, or</span></span><br><span class="line"><span class="comment"> * "rw" for reading and writing.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> file the file</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> mode the mode</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException the io exception</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">BufferedRandomAccessFile</span><span class="params">(File file, String mode)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">this</span>(file, mode, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Instantiates a new Buffered random access file.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> file the file</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> mode the mode</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> size the size</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException the io exception</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">BufferedRandomAccessFile</span><span class="params">(File file, String mode, <span class="keyword">int</span> size)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">super</span>(file, mode);</span><br><span class="line"> path_ = file.getAbsolutePath();</span><br><span class="line"> <span class="keyword">this</span>.init(size);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Open a new <code>BufferedRandomAccessFile</code> on the file named</span></span><br><span class="line"><span class="comment"> * <code>name</code> in mode <code>mode</code>, which should be "r" for</span></span><br><span class="line"><span class="comment"> * reading only, or "rw" for reading and writing.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> name the name</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> mode the mode</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException the io exception</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">BufferedRandomAccessFile</span><span class="params">(String name, String mode)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">this</span>(name, mode, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Instantiates a new Buffered random access file.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> name the name</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> mode the mode</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> size the size</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> FileNotFoundException the file not found exception</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">BufferedRandomAccessFile</span><span class="params">(String name, String mode, <span class="keyword">int</span> size)</span> <span class="keyword">throws</span> FileNotFoundException </span>{</span><br><span class="line"> <span class="keyword">super</span>(name, mode);</span><br><span class="line"> path_ = name;</span><br><span class="line"> <span class="keyword">this</span>.init(size);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">(<span class="keyword">int</span> size)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.dirty_ = <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">this</span>.lo_ = <span class="keyword">this</span>.curr_ = <span class="keyword">this</span>.hi_ = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">this</span>.buff_ = (size > BUFF_SZ) ? <span class="keyword">new</span> <span class="keyword">byte</span>[size] : <span class="keyword">new</span> <span class="keyword">byte</span>[BUFF_SZ];</span><br><span class="line"> <span class="keyword">this</span>.maxHi_ = (<span class="keyword">long</span>) BUFF_SZ;</span><br><span class="line"> <span class="keyword">this</span>.hitEOF_ = <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">this</span>.diskPos_ = <span class="number">0L</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Gets path.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the path</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getPath</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> path_;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Sync.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException the io exception</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sync</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">if</span> (syncNeeded_) {</span><br><span class="line"> flush();</span><br><span class="line"> getChannel().force(<span class="keyword">true</span>);</span><br><span class="line"> syncNeeded_ = <span class="keyword">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">close</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">this</span>.flush();</span><br><span class="line"> <span class="keyword">this</span>.buff_ = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">super</span>.close();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Flush any bytes in the file's buffer that have not yet been written to</span></span><br><span class="line"><span class="comment"> * disk. If the file was created read-only, this method is a no-op.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException the io exception</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">flush</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">this</span>.flushBuffer();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Flush any dirty bytes in the buffer to disk.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">flushBuffer</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.dirty_) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.diskPos_ != <span class="keyword">this</span>.lo_) {</span><br><span class="line"> <span class="keyword">super</span>.seek(<span class="keyword">this</span>.lo_);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">int</span> len = (<span class="keyword">int</span>) (<span class="keyword">this</span>.curr_ - <span class="keyword">this</span>.lo_);</span><br><span class="line"> <span class="keyword">super</span>.write(<span class="keyword">this</span>.buff_, <span class="number">0</span>, len);</span><br><span class="line"> <span class="keyword">this</span>.diskPos_ = <span class="keyword">this</span>.curr_;</span><br><span class="line"> <span class="keyword">this</span>.dirty_ = <span class="keyword">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Read at most "this.buff.length" bytes into "this.buff", returning the</span></span><br><span class="line"><span class="comment"> * number of bytes read. If the return result is less than</span></span><br><span class="line"><span class="comment"> * "this.buff.length", then EOF was read.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">fillBuffer</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">int</span> cnt = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">int</span> rem = <span class="keyword">this</span>.buff_.length;</span><br><span class="line"> <span class="keyword">while</span> (rem > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">int</span> n = <span class="keyword">super</span>.read(<span class="keyword">this</span>.buff_, cnt, rem);</span><br><span class="line"> <span class="keyword">if</span> (n < <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> cnt += n;</span><br><span class="line"> rem -= n;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> ((cnt < <span class="number">0</span>) && (<span class="keyword">this</span>.hitEOF_ = (cnt < <span class="keyword">this</span>.buff_.length))) {</span><br><span class="line"> <span class="comment">// make sure buffer that wasn't read is initialized with -1</span></span><br><span class="line"> Arrays.fill(<span class="keyword">this</span>.buff_, cnt, <span class="keyword">this</span>.buff_.length, (<span class="keyword">byte</span>) <span class="number">0xff</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">this</span>.diskPos_ += cnt;</span><br><span class="line"> <span class="keyword">return</span> cnt;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * This method positions <code>this.curr</code> at position <code>pos</code>.</span></span><br><span class="line"><span class="comment"> * If <code>pos</code> does not fall in the current buffer, it flushes the</span></span><br><span class="line"><span class="comment"> * current buffer and loads the correct one.<p></span></span><br><span class="line"><span class="comment"> * <p></span></span><br><span class="line"><span class="comment"> * On exit from this routine <code>this.curr == this.hi</code> iff <code>pos</code></span></span><br><span class="line"><span class="comment"> * is at or past the end-of-file, which can only happen if the file was</span></span><br><span class="line"><span class="comment"> * opened in read-only mode.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">seek</span><span class="params">(<span class="keyword">long</span> pos)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">if</span> (pos >= <span class="keyword">this</span>.hi_ || pos < <span class="keyword">this</span>.lo_) {</span><br><span class="line"> <span class="comment">// seeking outside of current buffer -- flush and read</span></span><br><span class="line"> <span class="keyword">this</span>.flushBuffer();</span><br><span class="line"> <span class="keyword">this</span>.lo_ = pos & BUFF_MASK; <span class="comment">// start at BuffSz boundary</span></span><br><span class="line"> <span class="keyword">this</span>.maxHi_ = <span class="keyword">this</span>.lo_ + (<span class="keyword">long</span>) <span class="keyword">this</span>.buff_.length;</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.diskPos_ != <span class="keyword">this</span>.lo_) {</span><br><span class="line"> <span class="keyword">super</span>.seek(<span class="keyword">this</span>.lo_);</span><br><span class="line"> <span class="keyword">this</span>.diskPos_ = <span class="keyword">this</span>.lo_;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">int</span> n = <span class="keyword">this</span>.fillBuffer();</span><br><span class="line"> <span class="keyword">this</span>.hi_ = <span class="keyword">this</span>.lo_ + (<span class="keyword">long</span>) n;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// seeking inside current buffer -- no read required</span></span><br><span class="line"> <span class="keyword">if</span> (pos < <span class="keyword">this</span>.curr_) {</span><br><span class="line"> <span class="comment">// if seeking backwards, we must flush to maintain V4</span></span><br><span class="line"> <span class="keyword">this</span>.flushBuffer();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">this</span>.curr_ = pos;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">getFilePointer</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.curr_;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * max accounts for the case where we have written past the old file length, but not yet flushed our buffer</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">length</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">return</span> Math.max(<span class="keyword">this</span>.curr_, <span class="keyword">super</span>.length());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">if</span> (readEnd()) {</span><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">byte</span> res = <span class="keyword">this</span>.buff_[(<span class="keyword">int</span>) (<span class="keyword">this</span>.curr_ - <span class="keyword">this</span>.lo_)];</span><br><span class="line"> <span class="keyword">this</span>.curr_++;</span><br><span class="line"> <span class="keyword">return</span> ((<span class="keyword">int</span>) res) & <span class="number">0xFF</span>; <span class="comment">// convert byte -> int</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">(<span class="keyword">byte</span>[] b)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.read(b, <span class="number">0</span>, b.length);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">(<span class="keyword">byte</span>[] b, <span class="keyword">int</span> off, <span class="keyword">int</span> len)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">if</span> (readEnd()) {</span><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> len = Math.min(len, (<span class="keyword">int</span>) (<span class="keyword">this</span>.hi_ - <span class="keyword">this</span>.curr_));</span><br><span class="line"> <span class="keyword">int</span> buffOff = (<span class="keyword">int</span>) (<span class="keyword">this</span>.curr_ - <span class="keyword">this</span>.lo_);</span><br><span class="line"> System.arraycopy(<span class="keyword">this</span>.buff_, buffOff, b, off, len);</span><br><span class="line"> <span class="keyword">this</span>.curr_ += len;</span><br><span class="line"> <span class="keyword">return</span> len;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">readEnd</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.curr_ >= <span class="keyword">this</span>.hi_) {</span><br><span class="line"> <span class="comment">// test for EOF</span></span><br><span class="line"> <span class="comment">// if (this.hi < this.maxHi) return -1;</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.hitEOF_) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// slow path -- read another buffer</span></span><br><span class="line"> <span class="keyword">this</span>.seek(<span class="keyword">this</span>.curr_);</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.curr_ == <span class="keyword">this</span>.hi_) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(<span class="keyword">int</span> b)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.curr_ >= <span class="keyword">this</span>.hi_) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.hitEOF_ && <span class="keyword">this</span>.hi_ < <span class="keyword">this</span>.maxHi_) {</span><br><span class="line"> <span class="comment">// at EOF -- bump "hi"</span></span><br><span class="line"> <span class="keyword">this</span>.hi_++;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// slow path -- write current buffer; read next one</span></span><br><span class="line"> <span class="keyword">this</span>.seek(<span class="keyword">this</span>.curr_);</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.curr_ == <span class="keyword">this</span>.hi_) {</span><br><span class="line"> <span class="comment">// appending to EOF -- bump "hi"</span></span><br><span class="line"> <span class="keyword">this</span>.hi_++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">this</span>.buff_[(<span class="keyword">int</span>) (<span class="keyword">this</span>.curr_ - <span class="keyword">this</span>.lo_)] = (<span class="keyword">byte</span>) b;</span><br><span class="line"> <span class="keyword">this</span>.curr_++;</span><br><span class="line"> <span class="keyword">this</span>.dirty_ = <span class="keyword">true</span>;</span><br><span class="line"> syncNeeded_ = <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(<span class="keyword">byte</span>[] b)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">this</span>.write(b, <span class="number">0</span>, b.length);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(<span class="keyword">byte</span>[] b, <span class="keyword">int</span> off, <span class="keyword">int</span> len)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">while</span> (len > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">int</span> n = <span class="keyword">this</span>.writeAtMost(b, off, len);</span><br><span class="line"> off += n;</span><br><span class="line"> len -= n;</span><br><span class="line"> <span class="keyword">this</span>.dirty_ = <span class="keyword">true</span>;</span><br><span class="line"> syncNeeded_ = <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Write at most "len" bytes to "b" starting at position "off", and return</span></span><br><span class="line"><span class="comment"> * the number of bytes written.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">writeAtMost</span><span class="params">(<span class="keyword">byte</span>[] b, <span class="keyword">int</span> off, <span class="keyword">int</span> len)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.curr_ >= <span class="keyword">this</span>.hi_) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.hitEOF_ && <span class="keyword">this</span>.hi_ < <span class="keyword">this</span>.maxHi_) {</span><br><span class="line"> <span class="comment">// at EOF -- bump "hi"</span></span><br><span class="line"> <span class="keyword">this</span>.hi_ = <span class="keyword">this</span>.maxHi_;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// slow path -- write current buffer; read next one</span></span><br><span class="line"> <span class="keyword">this</span>.seek(<span class="keyword">this</span>.curr_);</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.curr_ == <span class="keyword">this</span>.hi_) {</span><br><span class="line"> <span class="comment">// appending to EOF -- bump "hi"</span></span><br><span class="line"> <span class="keyword">this</span>.hi_ = <span class="keyword">this</span>.maxHi_;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> len = Math.min(len, (<span class="keyword">int</span>) (<span class="keyword">this</span>.hi_ - <span class="keyword">this</span>.curr_));</span><br><span class="line"> <span class="keyword">int</span> buffOff = (<span class="keyword">int</span>) (<span class="keyword">this</span>.curr_ - <span class="keyword">this</span>.lo_);</span><br><span class="line"> System.arraycopy(b, off, <span class="keyword">this</span>.buff_, buffOff, len);</span><br><span class="line"> <span class="keyword">this</span>.curr_ += len;</span><br><span class="line"> <span class="keyword">return</span> len;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p><code>需求</code>:正在开发一个监控系统,要求将多台日志信息实时采集出来,然后保存到Kafka中,后期对日志数据进行spark运算、大数据处理分析,日志按大小,时间切分。</p>
<p><code>运用的技术</code>:RandomAccessFile类中seek方法可以从指定位置读取文件,可以用来实现文件实时读取,JDK文档有对RandomAccessFile的介绍。</p>
<p><code>思想</code>:在每一次读取后,close一下就不会影响重命名操作了。因为日志是线上机器产生的,我们只需要写实时读取的方法即可,但是这里为了模拟实际情况,也把产生日志的方法出来,在测试的时候,可以手动改变日志的名称,更为方便的处理方式—–将日志mock.log直接删除即可。</p>
<p><code>原生RandomAccessFile效率较低,后面附有BufferedRandomAccessFile</code></p>
<p>模拟写日志的类<br>因为日志是按大小和时间切分的,在测试的时候,直接修改日志的名称,或者删除日志。<br>
</summary>
<category term="Java" scheme="http://kunxiang.wang/categories/Java/"/>
<category term="Java" scheme="http://kunxiang.wang/tags/Java/"/>
</entry>
<entry>
<title>Java多线程读写HashMap遇到的坑</title>
<link href="http://kunxiang.wang/2019/03/29/Java%E5%A4%9A%E7%BA%BF%E7%A8%8B%E8%AF%BB%E5%86%99HashMap%E9%81%87%E5%88%B0%E7%9A%84%E5%9D%91/"/>
<id>http://kunxiang.wang/2019/03/29/Java多线程读写HashMap遇到的坑/</id>
<published>2019-03-29T06:55:09.000Z</published>
<updated>2019-03-29T06:55:09.897Z</updated>
<summary type="html">
</summary>
</entry>
<entry>
<title>Python中如何表示正负无穷大</title>
<link href="http://kunxiang.wang/2019/03/15/Python%E4%B8%AD%E5%A6%82%E4%BD%95%E8%A1%A8%E7%A4%BA%E6%AD%A3%E8%B4%9F%E6%97%A0%E7%A9%B7%E5%A4%A7/"/>
<id>http://kunxiang.wang/2019/03/15/Python中如何表示正负无穷大/</id>
<published>2019-03-15T08:12:43.000Z</published>
<updated>2019-03-15T08:17:59.432Z</updated>
<content type="html"><![CDATA[<h4 id="cmath-inf"><a href="#cmath-inf" class="headerlink" title="cmath.inf"></a>cmath.inf</h4><p>Floating-point positive infinity. Equivalent to <code>float('inf')</code>.<br>负无穷-float(‘-inf’)</p><p>New in version 3.6.</p><a id="more"></a><h4 id="cmath-pi"><a href="#cmath-pi" class="headerlink" title="cmath.pi"></a>cmath.pi</h4><p>The mathematical constant π, as a float.</p><h4 id="cmath-e"><a href="#cmath-e" class="headerlink" title="cmath.e"></a>cmath.e</h4><p>The mathematical constant e, as a float.</p><h4 id="cmath-tau"><a href="#cmath-tau" class="headerlink" title="cmath.tau"></a>cmath.tau</h4><p>The mathematical constant τ, as a float.</p><p>New in version 3.6.</p><h4 id="cmath-infj"><a href="#cmath-infj" class="headerlink" title="cmath.infj"></a>cmath.infj</h4><p>Complex number with zero real part and positive infinity imaginary part. Equivalent to <code>complex(0.0, float('inf'))</code>.</p><p>New in version 3.6.</p><h4 id="cmath-nan"><a href="#cmath-nan" class="headerlink" title="cmath.nan"></a>cmath.nan</h4><p>A floating-point “not a number” (NaN) value. Equivalent to <code>float('nan')</code>.</p><p>New in version 3.6.</p><h4 id="cmath-nanj"><a href="#cmath-nanj" class="headerlink" title="cmath.nanj"></a>cmath.nanj</h4><p>Complex number with zero real part and NaN imaginary part. Equivalent to complex(0.0, float(‘nan’)).</p><p>New in version 3.6.</p>]]></content>
<summary type="html">
<h4 id="cmath-inf"><a href="#cmath-inf" class="headerlink" title="cmath.inf"></a>cmath.inf</h4><p>Floating-point positive infinity. Equivalent to <code>float(&#39;inf&#39;)</code>.<br>负无穷-float(‘-inf’)</p>
<p>New in version 3.6.</p>
</summary>
<category term="Python3 进阶" scheme="http://kunxiang.wang/categories/Python3-%E8%BF%9B%E9%98%B6/"/>
<category term="Python3" scheme="http://kunxiang.wang/tags/Python3/"/>
</entry>
<entry>
<title>进程地址空间</title>
<link href="http://kunxiang.wang/2019/02/21/%E8%BF%9B%E7%A8%8B%E5%9C%B0%E5%9D%80%E7%A9%BA%E9%97%B4/"/>
<id>http://kunxiang.wang/2019/02/21/进程地址空间/</id>
<published>2019-02-21T13:32:36.000Z</published>
<updated>2019-02-21T13:33:14.795Z</updated>
<content type="html"><![CDATA[<p><img src="https://upload-images.jianshu.io/upload_images/2952111-0eb79a7aa48b7b29.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="process address space.png"></p>]]></content>
<summary type="html">
<p><img src="https://upload-images.jianshu.io/upload_images/2952111-0eb79a7aa48b7b29.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"
</summary>
<category term="操作系统" scheme="http://kunxiang.wang/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
<category term="多任务处理" scheme="http://kunxiang.wang/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E5%A4%9A%E4%BB%BB%E5%8A%A1%E5%A4%84%E7%90%86/"/>
<category term="操作系统" scheme="http://kunxiang.wang/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
</entry>
</feed>