【iOS】块与大中枢派发

news2024/9/22 7:36:40

文章目录

    • @[TOC](文章目录)
  • 前言
  • 理解“块”这一概念
    • 块的基础知识
    • 块的内部结构
    • 全局块,栈块,堆块
  • 为常用的块类型创建typedef
  • 用handler块降低代码分散程度
  • 用块引用其所属对象时不要出现保留环
  • 多用派发系列,少用同步锁
  • 多用GCD,少用performSelector方法
  • 掌握GCD及操作对列的使用时机
  • 通过Dispatch Group机制,根据系统资源状况执行任务
  • 使用dispatch_once来执行只需运行一次的线程安全代码
  • 不要使用dispatch_get_current_queue

前言

块与大中枢派发

开发应用程序时,应该多留意多线程问题。即使开发的应用程序用不到多线程,他们仍可能是多线程的,因为系统框架通常会在UI线程之外再使用一些线程来执行任务。
当前多线程编程的核心是“块”与“大中枢派发”。块是一种可以在C,C++,及Objective-C代码中使用的“词法闭包”,借此机制,开发者可以将代码像对象一样传递,令其在不同环境下运行。在定义“块”的范围内,它可以访问到其中的全部变量
GCD是一种与块有关的技术,它提供了对线程的抽象,这种抽象基于“派发队列”。开发者可以将块排入队列中,由GCD负责处理所以调度事宜。GCD会根据系统资源情况,适时的创建,复用,摧毁后台线程,以便处理每个队列。GCD还可以方便的完成常见编程任务,比如编写“只执行一次线程安全的代码”或者根据可用的系统之一来兵法之行多个操作。


提示:以下是本篇文章正文内容,下面案例可供参考

理解“块”这一概念

  • “块”可以实现闭包。这项特性是作为”拓展“加入GCC编译器中的,在近期版本中的Clang中都可以使用。这是一个位于C语言层面的特性,因此,只要有支持此特性的编译器,以及能执行块的运行期组件,就可以在C,C++,Objective-C,Objective-C++,代码中使用。

块的基础知识

  • 块与函数类似,块是直接定义在另一个函数里表示的。和定义它的那个函数共享同一个范围内的东西。块用符号“^”来表示。后面跟着一对花括号,括号里是块的实现代码。
  • 块其实就是一个值,而且有其相关类型。与int,float,或Objectiove-C对象一样,也可以把这个歌块付给变量,然后像使用其他变量那样使用它。块类型的语法与函数类。
void (^someBlock) () = ^{
    
};
  • 定义了一个名为someBlock的变量。由于变量名写在正中间,所以看上去有点怪。
return_type (^block_name)(parameters)


int (^addBlock)(int a, int b) = ^(int a, int b){
    return a + b;
};


int add = addBlock(2,5);
//add = 7;
  • 块的强大之处在于:声明他的范围里,所以变量都可以为其所捕获。也就是说,那个范围里的全部变量,在块里仍然可以使用。默认情况下,为快所捕获的变量,是不可以在块里修改的。如果声明变量的时候加上_bolk修饰符,就可以在块内修改了。
  • 如果块所捕获的变量是对象类型,那么就会自动保留它。系统在释放这个块的时候,也会将其一并释放。块本身可以视作对象,实际上在其他OC所能响应的选择子中途,有很多块也可以响应。最重要的是:块本身也和其他对象一样,有引用计数。当最后一个指向块的引用移走之后,块就回收了。回收时也会释放块所捕获的变量。以便平衡捕获时所执行的保留操作。
  • 如果将块定义在Objective-C类的实例丰富中,那么除了可以访问类的所以实例变量之外,还可以使用self变量。块总能修改实例变量,所以在声明时无需加_block。如果通过读取或写入操作捕获了实例变量,那么也会自动把self变量一并捕获。因为实例变量时与self所指代的实例关联在一起的。
  • self也是一个对象,块在捕获它时也会将其保留。如果self所指代的那个对象同时也保留了块,那么这种情况通常会导致“保留环”。

块的内部结构

  • 每个Objective-C对象都占据着某个内存区域。因为实例变量的个数及对象所包含的关联数据互不相同,所以每个对象所占内存区域也有大有小。块本身是对象,在存放块对象的内存区域中,首个变量是指向Class对象的指针,叫做isa。其余内存里含有块对象政策运转所需的各种信息。请添加图片描述
  • 在内存布局中,最重要的是invoke变量。这是一个函数指针,指向块的实现代码。函数原型至少要接受一个void*型的参数,此参数代表块。块其实就是一种代替函数指针的语法结构,原来使用函数指针时,需要用不透明的void指针来传递状态。改用块之后,可以吧原来用标准的C语言特性所编的代码封装成简明且易用的接口。
  • descriptor变量指向结构体的指针,每个块里都包含此结构体。其中声明了块对象总体大小,还声明了copy与dispose这两个辅助函数所对应的函数指针。辅助函数在拷贝及丢弃块对象时运行,其中会执行一些操作,比方说,钱折腰保留捕获的对象,后者将之释放。
  • 块还会把他锁捕获的所有变量都拷贝一份。这些拷贝对象放在descriptor变量后面,捕获了多少个变量,就要占据多少内存空间。(拷贝的是 指向这些对象的指针变量)。因为执行块时,要把变量从内存中读出来,invoke函数需要把块作为对象传进来。

全局块,栈块,堆块

  • 定义块的时候,所占内存区域是分配在栈中的。块只在定义他的那个范围内有效。
  • 可以给块对象发送copy消息拷贝来解决这个问题。这样的话,就可以把块从栈复制到堆。拷贝后的块,可以定义在他的那个范围之外使用。一旦复制到堆上,块就变成了带引用计数的对象了。后续的复制操作都不会真的复制,只是递增块对象的引用计数。如果不在使用这个块,应该将其释放。在ARC环境下会自动释放,手动管理引用计数需要自己来调用release方法。当引用计数降为0后,“分配在堆上的块”会像其他对象一样,为系统所回收。“分配在栈上的块”无需明确释放。因为栈内存本来就会自动回收。
  • 全局块不会不做任何状态,运行时也无需有状态来参与。块所使用的整个内存区域,在编译期已经完全确定了。因此,全局块可以声明在全局内存里,而不需要在每次用到的时候与栈中创建。全局块的拷贝相当于一个空操作,因为全局块绝不可能为系统回收。相当于一个单例。

为常用的块类型创建typedef

  • 每个块都有用其固有类型,因而可以将其复制给适当类型的变量。这个类型由块所接受的参数机器返回值组成。
  • 与其它类型的变量不同,在定义块变量时,要把变量名放在类型之中,而不要放在右侧。可以起一个更为易读的名字来表示块,把块的类型隐藏在后面。
typedef int(^EOCSomeBlock) (BOOL flag, int value);
  • typedef关键字用于给类型起一个易读的名。
  • 声明变量时,要把名称放在类型中间,并在前面加上^符号,而定义新类型时也得这么做。上面的语句向系统中新增了一个名为EOCSomeBlock的类型,此后,直接使用新类型即可。
  • 与定义的其他变量一样,变量类型在左边,变量名在右边。 通过这个特性,可以把使用块的API做的更容易一些。类里面有些方法可能需要用块来做参数,比如执行异步任务时所用的completion handler。参数就是块,但凡遇到这种情况,都可以通过定义别名使代码更为易读。
  • 定义方法参数所用的块类型语法,又和定义变量时不同。若能把方法签名中的参数类型写成一个词,那么读起来就顺口多了。于是,可以给参数类型七个别名,然后使用此名称来定义。
  • 使用类型定义还有一个好处,就是当你打算重构块的类型签名时会很方便。
  • 最后在使用块类型的类中定义这些typedef,而且应该把这个类的名字加在由typedef所定义的新类型的后面。这样可以阐明块的用途。还可以用typedef给同一个块签名类型创建数个别名。
  • 如果由好几个类都要执行相似但各有区别的异步任务,而这几个类又不能防乳同一个体系继承,每个类就应该有自己的completion handler类型。这个几个completion handler的签名签名也许完全相同,但最好还是在每个类里都各自定义一个别名,而不要共用一个名称。繁殖,若这些类能纳入同一个继承中,则应该将类型定义语句放在超类中,供子类使用。

用handler块降低代码分散程度

  • 为用户界面编码时,常用范式“异步执行任务”。这种范式的有点在于:处理用户界面的现实及触摸操作所用的线程,不会因为要执行I/O或网络通信这类好事的任务而阻塞。这个线程通常称为主线程。如果把执行异步任务做成同步的,那么在执行任务时,用户界面就变得无法响应用户输入了。
  • 异步方法在执行完任务后,需要以某种手段通知相关代码。比如通过委托协议,令关注此事件的对象遵循该协议。对象成为delegate后,就可以在相关事件发生时得到通知。
  • 如果用块来写一个从URL中获取数据的类,嗲吗会更加氢气。块可以令这种API变得更为紧致,同时令开发者调用起来更方便。把completion handler定义为块类型,将其当作参数传递给方法。这种模式和委托协议很像,但是可以在调用方法时直接以内联形式定义completion handler,以此方式来使用“网络数据获取器”,可以令代码比原先易读
  • 与委托模式的代码相比。块写出来的代码更简洁。异步任务执行完毕后所需运行的业务逻辑,和启动一步任务所应的代码放在了一起。而且,由于块声明在创建获取器的范围里,所以它可以访问此范围内的全部变量。
  • 委托模式有一个缺点,如果类要分别使用多个获取器下载不同数据,那么就得在delegate回调方法里根据传入的获取器参数切换。这样做会令delegate回调方法变得很长,而且还要把网络数据获取器对象保存为实例变量。用块来改写的好处是:无需保存选择器,也无需在回调方法里切换。每个completion handler的业务逻辑,都是和相关的获取器对象一起来定义的。
  • 可以分别用两个处理程序来处理操作失败和成功的不同情况。也可以吧处理失败的情况所需的代码,与处理正常情况所用的代码,都封装到同一个completion handler块里。由于成功和失败的情况分开处理,所以调用此API的代码也会按照逻辑,吧应对成功和失败的代码分开来写,令代码可读性更高。
  • 如果把全部逻辑写在一起,会令块变得比较长,比较复杂。都是使用一个块来处理也更为灵活。调用API的代码也可能会在处理成功响应的过程中发现错误。如果把成功和失败情况交给老公不同的处理程序来负责,那么就没办法共享同一份错误处理代码里,除非吧这段代码单独放在一个方法里,但是这样违背了我们想把全部逻辑代码放在一处的初衷。
  • 有时候在相关事件点执行回调操作,这种情况也可以使用handler块。
  • 基于handler来设计API还有一个原因,某些代码必须运行在特定的线程上。因此,最好能由调用API的人来决定handler应该运行在哪个线程上。NSNotificationCenter就是这种APi,它提供了一个方法, 调用者可以经由此方法来注册想要接收的通知等到相关事件发生时,通知中心就会执行注册号的那个块。调用者可以指定某个块应该安排在哪个执行队列里。若没有指定队列,按照默认方法执行,也就是由投递通知的那个线程来执行。

用块引用其所属对象时不要出现保留环

  • 使用块时,若不仔细思量,很容易导致“保留环”。
  • 如果设计API时用到了completion handler这样的回调块,那么很容易形成保留环。一般来说,只要适时清理掉环中的某个引用,即可解决此问题。
  • 如果completion handler块所引用的对象最终又引用了这个块本身,那么就会出现保留环。
  • 如果块所捕获的对象直接或间接保留了块本身,那么就得当心保留环
  • 一定要找一个适当的时机解除保留环,而不能把责任推卸给API的调用者。

多用派发系列,少用同步锁

  • 在Objective-C中,如果有多个线程要执行同一份代码,那么又是可能会出现问题。这个时候通常使用锁实现同步机制。在GCD出现前,有两种方法。
  • 第一种是采用内置的“同步块”。这种写法会根据给定对象,自动创建一个锁,并等待块中的代码执行完毕,执行到代码结束时,锁就释放了。
  • 另一种方法是直接使用NSLock对象。也可以使用NSRecursiveLock这种“递归锁”,线程能够多次持有该锁,而不会出现死锁现象。
  • 在极端情况下,同步锁会导致死锁,效率也不一定提高,如果直接使用锁对象,一旦遇到死锁,就会非常麻烦。
  • 代替方案就是使用GCD,能更简单,更高效的为代码加锁。
  • 使用“串行同步队列”,将读取操作都安排在同一个队列里,即可保证数据同步。这种方法可以更简单,高效的代替同步块或锁对象。
  • 这种模式的思路是:把设置操作与获取操作都安排在序列化的队列里执行,这样的话,所有针对属性的访问操作就都同步了。为了使块代码能够设置局部变量,获取方法中用到了__block语法。若是抛开这一点,这种写法比签名那些更简洁。全部加锁任务都在GCD中处理,而GCD是在相当深的底层来实现的。于是能够做许多优化。
  • 还可以进行一步优化,设置方法不一定非得是同步的,设置实例变量所用的块,并不需要向设置方法返回什么值。
  • 把同步派发改为异步派发时,从调用者的角度看,这个小改动可以提升设置方法的执行速度,而读取操作与写入操作依然会按照顺序执行。但是也有一个坏处:这种写法比原来慢。因为执行异步派发时,需要拷贝块。若拷贝块的时间明显超过执行块的时间,真宗方法会比原来慢。
  • 多个获取方法可以并发执行,而获取次方法与设置方法之间不能并发执行,利用这个特点,可以写出来更快的代码。
  • 在队列中,栅栏块必须单独进行,不能与其他块并行。这只是对并发队列有意义,因为串行队列中的块总是按照顺序来逐个执行。并发队列如果发现接下来的要处理的块是栅栏块,那么就一直要等到当前所有的并发块都执行完毕,才会单独执行这个歌栅栏块。栅栏块执行完毕后,在按照正常方式继续向下执行。请添加图片描述
  • 这种做法肯定会比使用串行队列要快。注意,设置函数也可以改用同步的栅栏块来实现,这样可能更高细哦啊。最好还是测一测每种方式的性能,选择最好的。

多用GCD,少用performSelector方法

  • Objective-C本质上是一门非常动态的语言。NSObject定义了几个方法,可以随意调用。在出现了大中暑派发及块这样的新技术之后, 这几个方法就没有那么重要了。
  • 最简单的:-(id)performSelector:(SEL)selector
  • 与直接调用选择子等效。[object performSelector:@Selector(selectorName)];
    [object selectorName];
  • 这两行代码效果相同。
  • 如果某个方法只是这么来调用,此方法就有一点多余。如果选择子是在运行期决定的,就等于在动态绑定上再次使用动态绑定。
  • 还有一种用法,把选择子保存起来,等到某个事件发生之后在调用。不论哪个用法,编译器都不知道要执行的选择子是什么。必须等到运行期才能确定。但是在ARC环境下编译代码的话,编译器会发出警告。提示出现内存泄漏。因为编译器不知道将要调用的选择子是什么,也不了解方法签名和返回值,甚至不知道是不是有返回值。由于编译器不知道方法签名,也就没办法运用ARC的内存管理规则来判定返回值是不是应该释放。于是ARC不添加释放擦欧哦,这样做就可能导致内存泄漏,因为方法在返回对象时可能已经将其保留了。
  • 选择子最多只能接收两个参数,也就是调用“performSelector:withObject :withObject:”这个版本。在参数不止两个的时候,没有对应的performSelector方法能够执行此种选择子。
  • performSelector还可以延后执行选择子,或者将其放在另一个线程上进行。
  • 这些方法太过局限,具备延后执行的那些方法无法处理带有两个参数的选择子。能够指定执行线程的方法也不是很通用。
  • 如果改用其他方法,就没有这些限制。最常见的是改用块。performSelector系列方法提供的线程功能,都可以在大中枢派发机制中使用块来实现。延后执行可以使用dsidpatch_after来实现,在另一个线程上可以用dispatch_sync和dispatch_async来实现。

掌握GCD及操作对列的使用时机

  • 要了解每项技巧的使用时机,如果选错了工具,那么编出来的代码就会难以维护。
  • 对于那些只执行一次的代码来说,GCD的dispatch_once最为方便。在执行后台任务时,GCD不一定是最佳方式。还有一种技术叫做NSOperationQueue,开发者可以把操作以NSOperation的子类的形式放在队列中,这些操作也能并发执行。“操作队列”在GCD之前就有了,其中某些设计原理因操作队列流行,GCD就是基于这些原理构造的。
  • GCD是纯C的API,操作队列是Objective-C的对象。在GCD种,任务用块来表示,块是一个轻量级的数据结构。与之相反,操作是一个更重量级的Objective-C对象。但是GCD并不是总是最佳方案,有时候采用对象所带来的开销微乎其微,使用完整对象所带来的好处反而超过其缺点
  • 用NSOperationQueue类的“addOperationQueueWithBlock:”方法搭配NSB咯出口O普洱阿嚏哦你类来使用操作队列,语法和纯GCD类似。使用NSOperation和NSOperationQueue的好处如下:
    一:取消某个操作:如果使用操作队列,取消操作很容易。运行任务之前,可以在NSOperation对象上调用cancel方法,该方法会设置对象内的标志位,用以表明此任务不需要执行。已经启动的任务无法取消。若不使用操作队列,把块安排到GCD队列,就无法取消了。那套架构是“安排好任务之后就不管了”。开发者可以在应用程序层之间实现取消功能。这样做需要编写很多代码。
    二:指定操作间的依赖关系。一个操作可以包含其他多个操作。开发者能够指定操作之间的依赖关系,使特定的操作必须在另外一个操作顺利执行完毕后执行。
    三:通过键值观测机制监控NSOperation对象的属性。NSOperation对象有多个属性都适合使用KVO来监听。
    四:指定操作的优先级。操作的优先级便是此操作与队列中其他操作之间的优先关系。优先级高的操作先执行,优先级低的操作后执行。操作队列的调度方法虽不透明,但是必须经过一番深思熟虑在写成。GCD没有直接实现此功能的方法。但是GCD的队列确实有优先级。那是针对整个队列来说的,而不是针对每个块。NSOperation对象也有线程优先级,这决定了运行此操作的线程处在何种优先级上。用GCD也可以实现此功能,但是采用队列更简单,只要设置一个属性即可。
    五:崇勇NSOpera提哦你对象。系统内设置了一些NSOperation对象的子类供开发者使用。这些子类就是普通的Objective-C对象,能够存放任何信息。对象在执行时可以充分利用存于其中的信息,而且还可以随意调用定义在类中的方法。
  • 操作队列有很多地方都胜过派发队列。操作队列提供了多种执行任务的方法,都是写好的,直接就能用。开发者不在编写复杂的调度器,也不用自己来实现取消操作或指定操作的优先级的功能。
  • 有一个API选用了操作队列而非派发队列,NSNotificationCenter。开发者可以注册监听器,以便在发生相关事件时得到通知。这个方法接收的参数类型是块,不是选择子。

通过Dispatch Group机制,根据系统资源状况执行任务

  • dispatch group是GCD的一项特性,能够把任务分组。调用者可以等待着族任务执行完毕,也可以在提供回调函数之后继续往下执行,这组任务完成时,调用者会接到通知。这个功能有许多用途,最重要的是吧将要并发执行的多个任务合为一组,调用者就可以知道这些任务何时能全部执行完毕。
  • dispatch group就是一个简单的数据结构,这种结构彼此之间没有什么区别,它不像派发队列,后者还有一个区别身份的标识符。想把数组编组,有两种方法。第一种是利用函数。请添加图片描述
    他是普通dispatch_async函数的辩题,比原来多一个参数,用于表示带执行的块所属的组。
    请添加图片描述
    前者能够使分组里正要执行的任务数递增,后者使其递减。调用前者之后,必须调用后者。和引用计数类似。请添加图片描述
    此函数接收两个参数,一个是要等待的group,另一个是代表等待时间的timeout。timeout表示函数在等待dispatch group执行完毕时,应该阻塞多久。如果执行dispatch group所用时间小于timeout,返回0,否则返回非0值。请添加图片描述
    也可以使用这个函数等待dispatch group执行完毕。开发者可以向此函数传入块,等dispatch group执行完毕后,块会在特定的线程上执行。假如当前线程不应阻塞,开发者又想在那些任务全部完成时得到通知,此做法就很有必要。
  • 一系列任务可归入一个dispatch group之中,开发者可以在这组任务执行完毕时获得通知。
  • 通过dispatch group,可以在并发式派发队列里同时执行多项任务。此时GCD会根据系统资源状况调度这些并发执行的任务。

使用dispatch_once来执行只需运行一次的线程安全代码

  • 单例模式的常见实现模式为:在类中编写方法,该方法只会返回全类公用的单例实例,不会每次调用时都创建出新的实例。
  • 为保证线程安全,上述代码将创建单例实例的代码包裹在同步块里。请添加图片描述
  • GCD使用这个函数让实现单例模式更容易。此函数接收类型为dispatch_once_t的特殊参数,还接收块参数。对于给定的标记来说,该函数保证相关的块必定执行,且仅执行一次。首次调用这个函数时,必然执行其中的代码,最重要的是这个操作线程完全安全。对于只执行一次的函数来说,每次调用函数时传入的标记都必须完全相同。
  • dispatch_once可以简化代码并彻底保证线程安全,无需担心加锁或同步。所有问题都由GCD在底层处理。每次调用时都必须使用完全相同的标记,所以标记要声明成static。吧该变量定义在static作用域中,保证编译器每次执行sharedInstance方法时都会复用这个变量,不会创建新的变量。
  • dispatch_once更高效。他没有使用总量级的同步机制。采用“原子访问”来查询标记,来判断对应代码是否已经执行。

不要使用dispatch_get_current_queue

  • 使用GCD时,经常要判断当前的代码正在哪个队列上执行,向多个队列派发任务时也如此。
  • dispatch_queue_t dispatch_get_current_queue
  • 这个函数返回当前证在执行的队列。用一种典型的错误用法“反模式”,就是用它检测当前队列是不是某个特定的队列。试图以此避免执行同步派发时可能遭遇的死锁问题。请添加图片描述
  • dispatch_get_current_queue函数的行为常常和开发者预期的不同,此函数已经被废弃。只应该做调试之用。
  • 派发队列是按层级来阻止的,无法单独使用某个队列对象来描述“当前队列”这一概念。
  • dispatch_get_current_queue函数用于解决由不可重入的代码所引发的思索,但是能用此函数解决的问题,也能用“队列特定数据来解决”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/138464.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux/ARM下QT MQTT库的编译安装

💂 个人主页:风间琉璃🤟 版权: 本文由【风间琉璃】原创、在CSDN首发、需要转载请联系博主💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦目录 一、 Linux 环境下编译安装 二、 ARM Linux 环境下安装 一、 Linux 环境下…

破解分布式光伏运维难题,光伏+屋面数字化监控融合是关键

2022年5月,在东南地区某城市一幢写字楼上,技术人员们正不辞辛苦爬上数十米高的墙面,对写字楼的屋面和墙面进行勘察。随后,他们准备赶在台风季来临之前完成该写字楼的建筑光伏一体化项目安装与部署。 这是森特士兴集团股份有限公司…

fixed:error:0308010C:digital envelope routines::unsupported

目录1.故障现场2. 问题分析3. 修复方案4. 参考文献1.故障现场 最近由于一些原因,从Mac OSX 迁移到 Windows 平台,在尝试运行基于vue-element-admin 项目时,发生了如下异常: error:0308010C:digital envelope routines::unsuppor…

MySQL的一些指令,函数以及关键字

这个里面我准备记录一些比较有意思的MySQL的指令和函数,当然使用函数的时候我们要注意,会不会因为函数导致不走索引,走全表扫描的情况。 因为对索引字段做函数操作,可能会破坏索引值的有序性,因此优化器就决定放弃走树…

导读:21 世纪中叶的精准肿瘤学奇点?循环肿瘤细胞和单细胞测序?

Tips: 组学时代的循环肿瘤细胞:我们离实现“奇点”还有多远?(Br J Cancer,IF:9.075),原文链接: https://pubmed.ncbi.nlm.nih.gov/35273384/ 循环肿瘤细胞的生物学、脆弱性和临床应用&#xff0…

用javascript分类刷leetcode22.字典树(图文视频讲解)

目录 Trie树,即字典树,又称前缀树,是一种树形结构,典型应用是用于统计和排序大量的字符串(但不限于字符串),所以经常被搜索引擎用于文本词频统计。它的优先是,最大限度的减少无谓的…

数据挖掘与机器学习作业_06 决策树

决策树 步骤 1.计算不纯度2.选取不纯度最高的特征进行分支3.计算不纯度4.继续划分 from sklearn import tree from sklearn.model_selection import GridSearchCV from sklearn.model_selection import cross_val_score from sklearn.model_selection import train_test_spl…

单点登录 SSO 解决方案选型指南|身份云研究院

单点登录(SSO)是目前企业降本增效以及提升用户体验的主流选择方案。常规的单点登录指“登录一次,即可访问所有互相信任的应用,用户不再需要记住每一个应用的账号密码”,这有效解决了密码疲劳、登录效率等问题&#xff…

(深度学习快速入门)第三章第二节:通过一个二分类任务介绍完整的深度学习项目

文章目录一:数据集介绍二:一个完整的深度学习项目必备文件三:项目代码(1)config.py——超参数文件(2)preprocess——数据预处理文件(3)dataloader——数据集封装&#xf…

后端人眼中的Vue(一)

一、简介 1.1、Vue简介 ​ Vue是渐进式 JavaScript 框架,啥叫渐进式?渐进式意味着你可以将Vue作为你应用的一部分嵌入其中,或者如果你希望将更多的业务逻辑使用Vue实现,那么Vue的核心库以及其生态系统。比如CoreVue-routerVuexax…

Homekit智能家居DIY之智能灯泡

一、什么是智能灯 传统的灯泡是通过手动打开和关闭开关来工作。有时,它们可以通过声控、触控、红外等方式进行控制,或者带有调光开关,让用户调暗或调亮灯光。 智能灯泡内置有芯片和通信模块,可与手机、家庭智能助手、或其他智能…

RabbitMQ、Kafka、RocketMQ消息中间件对比总结

文章目录前言侧重点架构模型消息通讯其他对比总结参考文档前言 不论Kafka还是RabbitMQ和RocketMQ,作为消息中间件,其作用为应用解耦、异步通讯、流量削峰填谷等。 拿我之前参加的一个电商项目来说,订单消息通过MQ从订单系统到支付系统、库存…

ORB-SLAM2 --- KeyFrame::UpdateConnections 函数

目录 一、函数作用 二、函数流程 三、code 四、函数解析 一、函数作用 更新关键帧之间的连接图。 更新变量 mConnectedKeyFrameWeights:当前关键帧的共视信息,记录当前关键帧共视关键帧的信息(哪一帧和当前关键帧有共视,共视…

用C++实现十大经典排序算法

作者:billy 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 简介 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大…

喜报|知道创宇连续两年获评北京市企业创新信用领跑企业!

近日,2022年度北京市企业创新信用领跑名单正式发布。知道创宇凭借过硬的技术实力、创新能力及良好的企业信用记录成功入选2022年度北京市企业创新信用领跑企业。值得一提的是,这是知道创宇继2021年以来,连续两年获得此项殊荣。连续两年蝉联双…

CPU是如何执行程序的?

CPU是如何执行程序的?1、硬件结构介绍1.1、CPU1.2、内存1.3、总线1.4、输入/输出设备2、程序执行的基本过程3、a11执行的详细过程现代计算机的基本结构为五个部分:CPU、内存、总线、输入/输出设备。或许你了解了这些概念,但是你知道a11在计算…

【Kubernetes | Pod 系列】Pod 的镜像下载策略和 Pod 的生命周期 Ⅰ—— 理论

目录4. 镜像下载策略5. Pod 的生命周期5.1 Pod 生命期与特性说明5.2 Pod Phase 阶段说明备注5.3 容器状态说明(1)Waiting (等待)(2)Running(运行中)(3)Termin…

【回答问题】ChatGPT上线了!给我推荐20个比较流行的nlp预训练模型

目录给我推荐20个比较流行的nlp预训练模型给我推荐20个比较流行的nlp预训练模型源码给我推荐20个比较流行的nlp预训练模型 BERT (谷歌) GPT-2 (OpenAI) RoBERTa (Facebook) ALBERT (谷歌) ELECTRA (谷歌) XLNet (谷歌/纽约大学) T5 (OpenAI) Transformer-XL (谷歌/香港中文大学…

Qt音视频开发09-ffmpeg内核音视频同步

一、前言 用ffmpeg来做音视频同步,个人认为这个是ffmpeg基础处理中最难的一个,无数人就卡在这里,怎么也不准,本人也是尝试过网上各种demo,基本上都是渣渣,要么仅仅支持极其少量的视频文件比如收到的数据包…

【EdgeBox_tx1_tx2_E100】 PyTorch v1.8.0 torchvision v0.9.0 环境部署

简介:介绍PyTorch 环境 在 EHub_tx1_tx2_E100载板,TX1核心模块环境(Ubuntu18.04)下如何实现部署和测试,准备安装的环境是(PyTorch v1.8.0 torchvision v0.9.0)。 关于测试硬件EHub_tx1_tx2_E1…