「面向打野编程」iOS多线程:CGD

前言

参考网络其他文章而写,渣水平,抛砖引玉。

虽然Concurrent意思为并发,但由于队列的实际效果,以下称为并行队列。

当前iPhone的CPU核心数远小于GCD的线程池,故不讨论GCD的线程池,没有意义。

GCD = 主队列 + 并行队列 * n

异步串行队列 = 并行队列 * 1

1. 同异步队列

  • 主队列dispatch_get_main_queue()

  • 全局并行队列dispatch_get_global_queue(0, 0)

  • 串行队列dispatch_queue_t sQue = dispatch_queue_create("q1", DISPATCH_QUEUE_SERIAL);

  • 并行队列dispatch_queue_t cQue = dispatch_queue_create("q2", DISPATCH_QUEUE_CONCURRENT);

GCD 串行队列 并行队列
同步执行 抢占执行 抢占执行
异步执行 等待执行 并行执行
  • 同步 + 队列 = 主队列
  • (异步 + 并行) * n = 串行队列 * n
  • 串行(同步 + 自身) = 死锁(无法抢占)

同步执行:抢占当前主线程,不能在主线程中使用,会造成死锁。

异步执行:将任务加入队列末尾,或将任务加入新线程。


主队列并行队列互不影响,即使并行队列被长耗时任务占满,主队列依然畅通。

经过测试,全局并行队列与自定义并行队列并没有太多明显的区别。当全局并行队列占满核心后,自定义并行队列依然会陷入等待,无法并发。

dispatch_queue_t cQue = dispatch_queue_create("cq", DISPATCH_QUEUE_CONCURRENT);
for(int i = 0; i < 20; ++i) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for(int j = 1; j < INT_MAX; ++j);
for(int j = 1; j < INT_MAX; ++j);
printf("_");
});
}
for(int i = 0; i < 20; ++i) {
dispatch_async(cQue, ^{
printf("2");
});
}
________________22222222222222222222____

CPU的核心数量是有限的,当异步线程的数量主够多的时候,会退化为串行队列,并不会变为并发执行。对于多个长时间运行的并行线程,可能会因为占满处理器而导致其他线程任务的堆积,可以使用[NSThread sleepForTimeInterval:(NSTimeInterval)]手动分割控制阻塞实现伪并发操作来改善长时间等待。

[NSThread sleepForTimeInterval:(NSTimeInterval)]

dispatch_queue_t cQue = dispatch_queue_create("cq", DISPATCH_QUEUE_CONCURRENT);
for(int i = 0; i < 20; ++i) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for(int j = 1; j < INT_MAX>>1; ++j);
[NSThread sleepForTimeInterval:2];
for(int j = 1; j < INT_MAX>>1; ++j);
[NSThread sleepForTimeInterval:1];
for(int j = 1; j < INT_MAX>>1; ++j);
[NSThread sleepForTimeInterval:0.5];
for(int j = 1; j < INT_MAX>>1; ++j);
printf("_");
});
}
for(int i = 0; i < 20; ++i) {
dispatch_async(cQue, ^{
printf("2");
});
}
_____22222222222222222222_______________

手动分割

dispatch_queue_t cQue = dispatch_queue_create("cq", DISPATCH_QUEUE_CONCURRENT);
for(int i = 0; i < 20; ++i) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for(int j = 1; j < INT_MAX>>1; ++j);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for(int j = 1; j < INT_MAX>>1; ++j);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for(int j = 1; j < INT_MAX>>1; ++j);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for(int j = 1; j < INT_MAX>>1; ++j);
printf("_");
});
});
});
});
}
for(int i = 0; i < 20; ++i) {
dispatch_async(cQue, ^{
printf("2");
});
}
22222222222222222222____________________

2. 栅栏

  • 同步栅栏dispatch_barrier_async

  • 异步栅栏dispatch_barrier_async

栅栏对全局并行队列无效,只能操作自定义并行队列。想要运行此处的代码就需要完成先前的操作,是否同步的区别在于能否阻塞当前线程。千万不要对把同步栅栏运行在同个队列,会造成死锁。


同步栅栏

dispatch_queue_t cQue = dispatch_queue_create("q", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(cQue, ^{
for(int j = 1; j < INT_MAX; ++j);
puts("1");
});
dispatch_async(cQue, ^{
for(int j = 1; j < INT_MAX; ++j);
puts("2");
});
dispatch_async(cQue, ^{
for(int j = 1; j < INT_MAX; ++j);
puts("3");
});
dispatch_barrier_sync(cQue, ^{
NSLog(@"4");
});
puts("-----5-------");
3
2
1
4
-----5-------

异步栅栏

dispatch_queue_t cQue = dispatch_queue_create("q", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(cQue, ^{
for(int j = 1; j < INT_MAX; ++j);
puts("1");
});
dispatch_async(cQue, ^{
for(int j = 1; j < INT_MAX; ++j);
puts("2");
});
dispatch_async(cQue, ^{
for(int j = 1; j < INT_MAX; ++j);
puts("3");
});
dispatch_barrier_async(cQue, ^{
NSLog(@"4");
});
puts("-----5-------");
-----5-------
1
2
3
4

死锁

dispatch_queue_t cQue2 = dispatch_queue_create("q22", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(cQue2, ^{
dispatch_async(cQue2, ^{
puts("1");
});
dispatch_barrier_sync(cQue2, ^{
puts("----------");
});
dispatch_async(cQue2, ^{
puts("2");
});
});
1

3. 延迟执行

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//延迟0.5s执行
});

4. 一次性代码

只执行一次,但是需要注意不要出现相互调用,会出现死锁

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//code to be executed once
});

5. 快速遍历

不用手写循环,或同时执行多个相似的代码块,会阻塞当前线程。

dispatch_apply(6, dispatch_get_global_queue(0, 0), ^(size_t i) {
NSLog(@"%zu", i);
});
2017-12-15 11:34:56.748284+0800 GCD-OC[2266:105786] 1
2017-12-15 11:34:56.748260+0800 GCD-OC[2266:105750] 0
2017-12-15 11:34:56.748294+0800 GCD-OC[2266:105785] 2
2017-12-15 11:34:56.748302+0800 GCD-OC[2266:105788] 3
2017-12-15 11:34:56.749694+0800 GCD-OC[2266:105750] 4
2017-12-15 11:34:56.749703+0800 GCD-OC[2266:105786] 5

6. 信号量

控制最大并行数,或用于同步,然而容易被其他方法取代。

  • 创建信号量dispatch_semaphore_create(long value)

相当于并行数,运行同时执行的线程数。

  • 获取信号量dispatch_semaphore_wait(dispatch_semaphore_t _Nonnull dsema, dispatch_time_t timeout)

如果信号量,返回0表示获取成功,否则阻塞主线程开始等待,超过等待时间后继续执行代码。

  • 增加信号量dispatch_semaphore_signal(dispatch_semaphore_t _Nonnull dsema)

信号量+1。

dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
long a = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW);
puts(a ? "1" : "0");
a = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW);
puts(a ? "1" : "0");
dispatch_semaphore_signal(semaphore);
for(int i = 0; i < 6; ++i) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
long a = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
sleep(3);
NSLog(a ? @"YES" : @"NO");
dispatch_semaphore_signal(semaphore);
});
}
puts("----------");
0
1
----------
2017-12-15 15:55:11.589061+0800 GCD-OC[4209:250818] NO
2017-12-15 15:55:14.593238+0800 GCD-OC[4209:250816] NO
2017-12-15 15:55:17.594262+0800 GCD-OC[4209:250817] NO
2017-12-15 15:55:20.597262+0800 GCD-OC[4209:250815] NO
2017-12-15 15:55:23.599650+0800 GCD-OC[4209:250850] NO
2017-12-15 15:55:26.603327+0800 GCD-OC[4209:250851] NO

7. dispatch_group

先完成前面的任务,再执行最后一个任务。相当于异步栅栏,但可以将任务给予任意队列。

创建groupdispatch_group_t group = dispatch_group_create();

添加任务

dispatch_group_async(dispatch_group_t  _Nonnull group, dispatch_queue_t  _Nonnull queue, ^{
code
});

最终任务

dispatch_group_notify(dispatch_group_t  _Nonnull group, dispatch_queue_t  _Nonnull queue, ^{
code
});

dispatch_queue_t cQue1 = dispatch_queue_create("q11", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t cQue2 = dispatch_queue_create("q22", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, cQue1, ^(){
sleep(2);
puts("1");
});
dispatch_group_async(group, cQue2, ^(){
sleep(1);
puts("2");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^(){
puts("3");
});
puts("-------");
-------
2
1
3

*:first-child {
margin-top: 0 !important; }
body > *:last-child {
margin-bottom: 0 !important; }

a {
color: #4183C4; }
a.absent {
color: #cc0000; }
a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0; }

h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative; }

h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoMTMuMCAyMDEyMDMwNS5tLjQxNSAyMDEyLzAzLzA1OjIxOjAwOjAwKSAgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM2NjlDQjI4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM2NjlDQjM4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzY2OUNCMDg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzY2OUNCMTg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsQhXeAAAABfSURBVHjaYvz//z8DJYCRUgMYQAbAMBQIAvEqkBQWXI6sHqwHiwG70TTBxGaiWwjCTGgOUgJiF1J8wMRAIUA34B4Q76HUBelAfJYSA0CuMIEaRP8wGIkGMA54bgQIMACAmkXJi0hKJQAAAABJRU5ErkJggg==) no-repeat 10px center;
text-decoration: none; }

h1 tt, h1 code {
font-size: inherit; }

h2 tt, h2 code {
font-size: inherit; }

h3 tt, h3 code {
font-size: inherit; }

h4 tt, h4 code {
font-size: inherit; }

h5 tt, h5 code {
font-size: inherit; }

h6 tt, h6 code {
font-size: inherit; }

h1 {
font-size: 28px;
color: black; }

h2 {
font-size: 24px;
border-bottom: 1px solid #cccccc;
color: black; }

h3 {
font-size: 18px; }

h4 {
font-size: 16px; }

h5 {
font-size: 14px; }

h6 {
color: #777777;
font-size: 14px; }

p, blockquote, ul, ol, dl, li, table, pre {
margin: 15px 0; }

hr {
background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0;
border: 0 none;
color: #cccccc;
height: 4px;
padding: 0;
}

body > h2:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child + h2 {
margin-top: 0;
padding-top: 0; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
margin-top: 0;
padding-top: 0; }

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0; }

h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
margin-top: 0; }

li p.first {
display: inline-block; }
li {
margin: 0; }
ul, ol {
padding-left: 30px; }

ul :first-child, ol :first-child {
margin-top: 0; }

dl {
padding: 0; }
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px; }
dl dt:first-child {
padding: 0; }
dl dt > :first-child {
margin-top: 0; }
dl dt > :last-child {
margin-bottom: 0; }
dl dd {
margin: 0 0 15px;
padding: 0 15px; }
dl dd > :first-child {
margin-top: 0; }
dl dd > :last-child {
margin-bottom: 0; }

blockquote {
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
blockquote > :first-child {
margin-top: 0; }
blockquote > :last-child {
margin-bottom: 0; }

table {
padding: 0;border-collapse: collapse; }
table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
table tr:nth-child(2n) {
background-color: #f8f8f8; }
table tr th {
font-weight: bold;
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
table tr td {
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
table tr th :first-child, table tr td :first-child {
margin-top: 0; }
table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }

img {
max-width: 100%; }

span.frame {
display: block;
overflow: hidden; }
span.frame > span {
border: 1px solid #dddddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto; }
span.frame span img {
display: block;
float: left; }
span.frame span span {
clear: both;
color: #333333;
display: block;
padding: 5px 0 0; }
span.align-center {
display: block;
overflow: hidden;
clear: both; }
span.align-center > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center; }
span.align-center span img {
margin: 0 auto;
text-align: center; }
span.align-right {
display: block;
overflow: hidden;
clear: both; }
span.align-right > span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right; }
span.align-right span img {
margin: 0;
text-align: right; }
span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left; }
span.float-left span {
margin: 13px 0 0; }
span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right; }
span.float-right > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right; }

code, tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px; }

pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent; }

.highlight pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }

pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
pre code, pre tt {
background-color: transparent;
border: none; }

sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}

kbd {
display: inline-block;
padding: 3px 5px;
font-size: 11px;
line-height: 10px;
color: #555;
vertical-align: middle;
background-color: #fcfcfc;
border: solid 1px #ccc;
border-bottom-color: #bbb;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #bbb
}

* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:0 auto;
}
}
@media print {
table, pre {
page-break-inside: avoid;
}
pre {
word-wrap: break-word;
}
}
-->

「面向打野编程」iOS多线程:CGD的更多相关文章

  1. 「雕爷学编程」Arduino动手做(15)——手指侦测心跳模块

    37款传感器和模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器与模块,依照实践出真知(动手试试)的理念,以学习和交流为目的,这里准备 ...

  2. Python(三)基础篇之「模块&面向对象编程」

    [笔记]Python(三)基础篇之「模块&面向对象编程」 2016-12-07 ZOE    编程之魅  Python Notes: ★ 如果你是第一次阅读,推荐先浏览:[重要公告]文章更新. ...

  3. 「雕爷学编程」Arduino动手做(33)——ESP-01S无线WIFI模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  4. 「雕爷学编程」Arduino动手做(9)——火焰传感器模块

    37款传感器和模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器与模块,依照实践出真知(动手试试)的理念,以学习和交流为目的,这里准备 ...

  5. 「雕爷学编程」Arduino动手做(10)——敲击传感器模块

    37款传感器和模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器与模块,依照实践出真知(动手试试)的理念,以学习和交流为目的,这里准备 ...

  6. 「雕爷学编程」Arduino动手做(41)---激光接收管模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  7. 「雕爷学编程」Arduino动手做(40)——旋转编码器模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  8. 「雕爷学编程」Arduino动手做(39)——DS18B20温度传感器

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  9. 「雕爷学编程」Arduino动手做(38)——joystick双轴摇杆模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

随机推荐

  1. 给opencart产品页添加额外信息

    有时我们在开发opencart时需要给产品页添加一些额外的信息,第一种聪明的方法可以修改并调用已有字段,详细可以参考opencart3产品页调用upc/数量等信息:如果您的开发能力不错的话可以用第二种 ...

  2. mysql表类型导致的 setRollbackOnly() 事务不回滚

    在SpringBoot 中,使用事务非常简单,只需在方法上面加入 @Transactional  注解就可以实现.也可加在类上,此时则类中所有方法都支持事务. 而当我使用下面代码时,发现事务却没有回滚 ...

  3. 初识python爬虫框架Scrapy

    Scrapy,按照其官网(https://scrapy.org/)上的解释:一个开源和协作式的框架,用快速.简单.可扩展的方式从网站提取所需的数据. 我们一开始上手爬虫的时候,接触的是urllib.r ...

  4. 接口测试工具-tamper data

    1.火狐浏览器插件 安装:1)打开火狐浏览器-alt键-附加组件-搜索tamper data-安装-重启火狐浏览器-在工具下打开tamper data 使用:start tamper 示例:http: ...

  5. CJSON create.c

    #include <stdio.h> #include "cJSON.h" /* { "semantic": { "slots" ...

  6. 2018-2019-2 网络对抗技术 20165321 Exp5 MSF基础应用

    1. 实践内容(3.5分) 1.1一个主动攻击实践: (1分) 首先攻击Windows XP: 在攻击机kali输入msfconsole进入控制台,依次输入以下指令: msf > use exp ...

  7. PHP----------linux下如何安装redis扩展。安装redis可以在我的博客redis里面寻找。

    1.扩展下载地址:wget https://github.com/phpredis/phpredis/archive/develop.zip 2.下载完了以后解压压缩包 解压以后切换到 cd phpr ...

  8. 初学Python(二)

    -----------------------------------------------------2019.3.5-00:59--------------------------------- ...

  9. [React Native] change port when running react native

    Two ways to do that. First, use this module to do that, https://github.com/ktonon/react-native-port- ...

  10. Flask实战-留言板-安装虚拟环境、使用包组织代码

    Flask实战 留言板 创建项目目录messageboard,从GreyLi的代码中把Pipfile和Pipfile.lock文件拷贝过来,这两个文件中定义了虚拟环境中需要安装的包的信息和位置,进入m ...