【iOS】NSOperation、NSOperationQueue

文章目录

  • 前言
  • 一、NSOperation、NSOperationQueue 简介
  • 二、NSOperation、NSOperationQueue 操作和操作队列
  • 三、NSOperation
  • 四、NSOperationQueue
  • 五、NSOperationQueue 控制串行执行、并发执行
  • 六、 NSOperation 操作依赖
  • 七、NSOperation 优先级
  • 八、NSOperation、NSOperationQueue 线程间的通信
  • 九、NSOperation、NSOperationQueue 线程同步和线程安全
    • NSOperation、NSOperationQueue 非线程安全
    • NSOperation、NSOperationQueue 非线程安全
  • 十、NSOperation、NSOperationQueue 常用属性和方法归纳
    • NSOperation 常用属性和方法
    • NSOperationQueue 常用属性和方法


前言

寒假学习了GCD,前几天学习了NSThread,今天来学习iOS 多线程中 NSOperation、NSOperationQueue 的相关知识以及使用方法。

一、NSOperation、NSOperationQueue 简介

NSOperation、NSOperationQueue 是苹果提供给我们的一套多线程解决方案。
实际上 NSOperationNSOperationQueue 是基于 GCD 更高一层的封装,完全面向对象。但是比 GCD 更简单易用、代码可读性也更高。

NSOperation需要配合NSOperationQueue来实现多线程。

二、NSOperation、NSOperationQueue 操作和操作队列

由于NSOperation、NSOperationQueue 是GCD的更高级的封装,因此两者有一些相同的概念

  • 操作(Operation)
    执行操作,也就相当于我们在线程中执行的代码
    在GCD操作是放在Block中的,在 NSOperation 中,我们使用 NSOperation 子类 NSInvocationOperation、NSBlockOperation,或者自定义子类来封装操作
  • 操作队列(Operation Queues)
  • 这里的队列是指操作队列,即用来存放操作的队列。不同于GCD的先进先出,NSOperationQueue可以设置操作执行的优先级
  • 操作队列通过设置最大并发操作数(maxConcurrentOperationCount) 来控制并发、串行。
  • NSOperationQueue 为我们提供了两种不同类型的队列:主队列和自定义队列。主队列运行在主线程之上,而自定义队列在后台执行。

三、NSOperation

NSOperatino实现多线程的步骤如下:

  • 1、创建任务:先将需要执行的操作封装到NSOperation对象中。
  • 2、创建队列:创建NSOperationQueue
  • 3、将任务加入到队列中:将NSOperation对象添加到NSOperationQueue

在不使用 NSOperationQueue,单独使用 NSOperation 的情况下系统同步执行操作

- (void)applicationDidFinishLaunching:(UIApplication *)application {MyOperation *operation = [[MyOperation alloc] init];NSLog(@"Before operation start");[operation start];NSLog(@"After operation finish");
}

操作从开始到结束的输出都是按顺序且同步的。应用的执行将在 Before operation start 打印后直接开始 NSOperation,然后直到该操作完成后,才继续执行打印 After operation finish。由于 start 方法是同步执行的,所以它会阻塞当前线程直到操作完成。

//基本使用
- (void)testBaseNSOperation{//处理事务NSInvocationOperation *op =  [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(handleInvocation:) object:@"XN"]; // object是传递参数NSOperationQueue *queue = [[NSOperationQueue alloc] init];//操作加入队列[queue addOperation:op];   
}
- (void)handleInvocation:(id)operation{NSLog(@"%@ - %@", operation, [NSThread currentThread]);
}

NSOperation是个抽象类,实际运用时中需要使用它的子类

  • 1、使用子类NSInvocationOperation
//直接处理事务,不添加隐性队列
- (void)createNSOperation{//创建NSInvocationOperation对象并关联方法,之后start。NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomething:) object:@"xn"];[invocationOperation start];
}

在这里插入图片描述

当我们直接使用[invocationOperation start];时任务在主线程执行

  • 2、使用子类NSBlockOperation
- (void)useBlockOperation {// 1.创建 NSBlockOperation 对象NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程}}];// 2.调用 start 方法开始执行操作[op start];
}

在这里插入图片描述
在没有使用NSOperationQueue,同时没有使用addExecutionBlock方法时不会开启新线程执行操作

同时通过addExecutionBlock就可以开启新线程执行操作

如果添加的操作多的话, blockOperationWithBlock: 中的操作也可能会在其他线程(非当前主线程)中执行,这是由系统决定的

- (void)testNSBlockOperationExecution{// 1.创建 NSBlockOperation 对象NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程}}];// 2.添加额外的操作[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程}}];[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程}}];[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程}}];[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"5---%@", [NSThread currentThread]); // 打印当前线程}}];[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"6---%@", [NSThread currentThread]); // 打印当前线程}}];[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"7---%@", [NSThread currentThread]); // 打印当前线程}}];[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"8---%@", [NSThread currentThread]); // 打印当前线程}}];// 3.调用 start 方法开始执行操作[op start];
}

输出:
在这里插入图片描述
使用子类 NSBlockOperation,并调用方法 AddExecutionBlock: 的情况下,blockOperationWithBlock:方法中的操作 和 addExecutionBlock: 中的操作是在不同的线程中异步执行的

  • 3、定义继承自NSOperation的子类,通过实现内部相应的方法来封装任务。
//*********自定义继承自NSOperation的子类*********
@interface CJLOperation : NSOperation
@end@implementation CJLOperation
- (void)main{for (int i = 0; i < 3; i++) {NSLog(@"NSOperation的子类:%@",[NSThread currentThread]);}
}
@end//*********使用*********
- (void)cjl_testCJLOperation{//运用继承自NSOperation的子类 首先我们定义一个继承自NSOperation的类,然后重写它的main方法。CJLOperation *operation = [[CJLOperation alloc] init];[operation start];
}

输出:
在这里插入图片描述
可以看出:在没有使用 NSOperationQueue、在主线程单独使用自定义继承自 NSOperation 的子类的情况下,是在主线程执行操作,并没有开启新线程

四、NSOperationQueue

NSOperationQueue添加事务
NSOperationQueue有两种队列:主队列、其他队列。其他队列包含了 串行和并发

  • 主队列
    凡是添加到主队列中的操作,都会放到主线程中执行。
// 主队列获取方法
NSOperationQueue *queue = [NSOperationQueue mainQueue];
  • 自定义队列(非主队列)
    添加到这种队列中的操作,就会自动放到子线程中执行
    同时包含了:串行、并发功能。
// 自定义队列创建方法
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

将操作加入到队列中

上边我们说到 NSOperation 需要配合 NSOperationQueue 来实现多线程。

那么我们需要将创建好的操作加入到队列中去。总共有两种方法:
1、- (void)addOperation:(NSOperation *)op;
需要先创建操作,再将创建好的操作加入到创建好的队列中去。

/*** 使用 addOperation: 将操作加入到操作队列中*/
- (void)addOperationToQueue {// 1.创建队列NSOperationQueue *queue = [[NSOperationQueue alloc] init];// 2.创建操作// 使用 NSInvocationOperation 创建操作1NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task1) object:nil];// 使用 NSInvocationOperation 创建操作2NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task2) object:nil];// 使用 NSBlockOperation 创建操作3NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程}}];[op3 addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程}}];// 3.使用 addOperation: 添加所有操作到队列中[queue addOperation:op1]; // [op1 start][queue addOperation:op2]; // [op2 start][queue addOperation:op3]; // [op3 start]
}

使用 NSOperation 子类创建操作,并使用 addOperation: 将操作加入到操作队列后能够开启新线程,进行并发执行

NSOperationQueue 管理一个或多个 NSOperation 对象的执行。当你将 NSOperation 实例加入到 NSOperationQueue 时,你不需要手动创建和管理线程。操作队列自动处理这些细节。

2、- (void)addOperationWithBlock:(void (^)(void))block;
无需先创建操作,在 block 中添加操作,程序直接将包含操作的 block 加入到队列中

/*** 使用 addOperationWithBlock: 将操作加入到操作队列中*/- (void)addOperationWithBlockToQueue {// 1.创建队列NSOperationQueue *queue = [[NSOperationQueue alloc] init];// 2.使用 addOperationWithBlock: 添加操作到队列中[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程}}];[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程}}];[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程}}];
}

在这里插入图片描述
可以看出:使用 addOperationWithBlock: 将操作加入到操作队列后能够开启新线程,进行并发执行

五、NSOperationQueue 控制串行执行、并发执行

我们在上面演示了并发功能,我们来看一下它的串行功能如何实现

这里有个关键属性 maxConcurrentOperationCount ,叫做最大并发操作数。用来控制一个特定队列中可以有多少个操作同时参与并发执行。

注意:这里 maxConcurrentOperationCount 控制的不是并发线程的数量,而是一个队列中同时能并发执行的最大操作数。而且一个操作也并非只能在一个线程中运行,一个操作可能很长,可以将其分散在多个线程中执行,比如我们在子线程更新数据后在主线程更新UI。

最大并发操作数:maxConcurrentOperationCount

maxConcurrentOperationCount 默认情况下为-1,表示不进行限制,可进行并发执行
maxConcurrentOperationCount 为1时,队列为串行队列。只能串行执行。
maxConcurrentOperationCount 大于1时,队列为并发队列。操作并发执行,当然这个值不应超过系统限制,即使自己设置一个很大的值,系统也会自动调整为 min{自己设定的值,系统设定的默认最大值}。

/*** 设置 MaxConcurrentOperationCount(最大并发操作数)*/
- (void)setMaxConcurrentOperationCount {// 1.创建队列NSOperationQueue *queue = [[NSOperationQueue alloc] init];// 2.设置最大并发操作数queue.maxConcurrentOperationCount = 1; // 串行队列
// queue.maxConcurrentOperationCount = 2; // 并发队列
// queue.maxConcurrentOperationCount = 8; // 并发队列// 3.添加操作[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程}}];[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程}}];[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程}}];[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程}}];
}

maxConcurrentOperationCount = 1
在这里插入图片描述

可以看到任务按顺序串行执行

maxConcurrentOperationCount = 2

在这里插入图片描述
并发操作数为2时可以执行两个操作,操作时并发施行的,而开启线程数量是由系统决定的,不需要我们来管理。

因为NSOperation由系统控制开启线程数量以及串行并行,而GCD需要我们手动控制

六、 NSOperation 操作依赖

NSOperation、NSOperationQueue 最吸引人的地方是它能添加操作之间的依赖关系。通过操作依赖,我们可以很方便的控制操作之间的执行先后顺序。NSOperation 提供了3个接口供我们管理和查看依赖。

  • (void)addDependency:(NSOperation *)op; 添加依赖,使当前操作依赖于操作 op 的完成。
  • (void)removeDependency:(NSOperation *)op; 移除依赖,取消当前操作对操作 op 的依赖。
  • @property (readonly, copy) NSArray<NSOperation *> *dependencies; 在当前操作开始执行之前完成执行的所有操作对象数组。

我们现在来假设一个场景,有两个操作A、B,A操作完B才能操作,也就是B依赖A

/*** 操作依赖* 使用方法:addDependency:*/
- (void)addDependency {// 1.创建队列NSOperationQueue *queue = [[NSOperationQueue alloc] init];// 2.创建操作NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程}}];NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程}}];// 3.添加依赖[op2 addDependency:op1]; // 让op2 依赖于 op1,则先执行op1,在执行op2// 4.添加操作到队列中[queue addOperation:op2];[queue addOperation:op1];
}

可以看到即使两个操作在不同线程执行也就是并发执行,也是op1先执行才能执行op2
在这里插入图片描述
去掉依赖:
在这里插入图片描述

七、NSOperation 优先级

NSOperation 提供了queuePriority(优先级)属性,queuePriority属性适用于同一操作队列中的操作

默认情况下,所有新创建的操作对象优先级都是NSOperationQueuePriorityNormal,但是我们可以通过setQueuePriority:方法来改变当前操作在同一队列中的执行优先级

// 优先级的取值
typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {NSOperationQueuePriorityVeryLow = -8L,NSOperationQueuePriorityLow = -4L,NSOperationQueuePriorityNormal = 0,NSOperationQueuePriorityHigh = 4,NSOperationQueuePriorityVeryHigh = 8
};

将操作添加到队列后操作会进入就绪状态,就绪状态的操作的执行顺序由操作之间的优先级决定

就绪状态的操作:简单理解就是准备就绪的操作就是没有需要依赖的操作,例如op2依赖于op1,那么op2就没有准备就绪,因为他需要等op1执行完才准备就绪

优先级不能取代依赖关系。如果要控制操作间的启动顺序,则必须使用依赖关系。

八、NSOperation、NSOperationQueue 线程间的通信

同样的我们在开发中常常在子线程中更新数据在主线程中更新UI,这在NSOperation中时如何实现的呢

/*** 线程间通信*/
- (void)communication {// 1.创建队列NSOperationQueue *queue = [[NSOperationQueue alloc]init];// 2.添加操作[queue addOperationWithBlock:^{// 异步进行耗时操作for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程}// 回到主线程[[NSOperationQueue mainQueue] addOperationWithBlock:^{// 进行一些 UI 刷新等操作for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程}}];}];
}

输出:
在这里插入图片描述

九、NSOperation、NSOperationQueue 线程同步和线程安全

又到了老生常谈的售票问题

NSOperation、NSOperationQueue 非线程安全

因为使用NSOperation将操作添加到队列时系统后自动执行并发操作
因此如果不对线程进行加锁会出现如下状况

/*** 非线程安全:不使用 NSLock* 初始化火车票数量、卖票窗口(非线程安全)、并开始卖票*/
- (void)initTicketStatusNotSave {NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程self.ticketSurplusCount = 50;// 1.创建 queue1,queue1 代表北京火车票售卖窗口NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];queue1.maxConcurrentOperationCount = 1;// 2.创建 queue2,queue2 代表上海火车票售卖窗口NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];queue2.maxConcurrentOperationCount = 1;// 3.创建卖票操作 op1__weak typeof(self) weakSelf = self;NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{[weakSelf saleTicketNotSafe];}];// 4.创建卖票操作 op2NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{[weakSelf saleTicketNotSafe];}];// 5.添加操作,开始卖票[queue1 addOperation:op1];[queue2 addOperation:op2];
}/*** 售卖火车票(非线程安全)*/
- (void)saleTicketNotSafe {while (1) {if (self.ticketSurplusCount > 0) {//如果还有票,继续售卖self.ticketSurplusCount--;NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@", self.ticketSurplusCount, [NSThread currentThread]]);[NSThread sleepForTimeInterval:0.2];} else {NSLog(@"所有火车票均已售完");break;}}
}

输出:
在这里插入图片描述

NSOperation、NSOperationQueue 非线程安全

使用互斥锁进行加锁后就得到了正确的票数

- (void)saleTicketNotSafe {while (1) {@synchronized (self) {if (self.ticketSurplusCount > 0) {//如果还有票,继续售卖self.ticketSurplusCount--;NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@", self.ticketSurplusCount, [NSThread currentThread]]);[NSThread sleepForTimeInterval:0.2];} else {NSLog(@"所有火车票均已售完");break;}}}
}

输出:
在这里插入图片描述

十、NSOperation、NSOperationQueue 常用属性和方法归纳

NSOperation 常用属性和方法

取消操作方法

  • - (void)cancel; 可取消操作,实质是标记 isCancelled 状态。

判断操作状态方法

  • - (BOOL)isFinished; 判断操作是否已经结束。
  • - (BOOL)isCancelled; 判断操作是否已经标记为取消。
  • - (BOOL)isExecuting; 判断操作是否正在在运行。
  • - (BOOL)isReady; 判断操作是否处于准备就绪状态,这个值和操作的依赖关系相关。

操作同步

  • -(void)waitUntilFinished; 阻塞当前线程,直到该操作结束。可用于线程执行顺序的同步。
  • - (void)setCompletionBlock:(void (^)(void))block; completionBlock 会在当前操作执行完毕时执行 completionBlock。
  • - (void)addDependency:(NSOperation *)op; 添加依赖,使当前操作依赖于操作 op 的完成。
  • - (void)removeDependency:(NSOperation *)op;移除依赖,取消当前操作对操作 op 的依赖。
  • @property (readonly, copy) NSArray<NSOperation *> *dependencies; 在当前操作开始执行之前完成执行的所有操作对象数组。

NSOperationQueue 常用属性和方法

取消/暂停/恢复操作

- (void)cancelAllOperations; 可以取消队列的所有操作。
- (BOOL)isSuspended; 判断队列是否处于暂停状态。 YES 为暂停状态,NO 为恢复状态。
- (void)setSuspended:(BOOL)b; 可设置操作的暂停和恢复,YES 代表暂停队列,NO 代表恢复队列。

操作同步

- (void)waitUntilAllOperationsAreFinished; 阻塞当前线程,直到队列中的操作全部执行完毕。

添加/获取操作

- (void)addOperationWithBlock:(void (^)(void))block; 向队列中添加一个 NSBlockOperation 类型操作对象。
- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait; 向队列中添加操作数组,wait 标志是否阻塞当前线程直到所有操作结束
- (NSArray *)operations; 当前在队列中的操作数组(某个操作执行结束后会自动从这个数组清除)。
- (NSUInteger)operationCount; 当前队列中的操作数。

获取队列

+ (id)currentQueue; 获取当前队列,如果当前线程不是在 NSOperationQueue 上运行则返回 nil。
+ (id)mainQueue; 获取主队列。

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

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

相关文章

一个JDBC小工具

pom.xml 结构 <properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><mysql5>5.1.44<…

服务器端优化-Redis内存划分和内存配置

6、服务器端优化-Redis内存划分和内存配置 当Redis内存不足时&#xff0c;可能导致Key频繁被删除、响应时间变长、QPS不稳定等问题。当内存使用率达到90%以上时就需要我们警惕&#xff0c;并快速定位到内存占用的原因。 有关碎片问题分析 Redis底层分配并不是这个key有多大&…

[信息收集]-端口扫描--Nmap

端口号 端口号的概念属于计算机网络的传输层&#xff0c;标识这些不同的应用程序和服务而存在的。通过使用不同的端口号&#xff0c;传输层可以将接收到的数据包准确地传递给目标应用程序。 80&#xff1a;HTTP&#xff08;超文本传输协议&#xff09;用于Web浏览器访问网页 …

jvm面试题30问

什么是JVM的跨平台&#xff1f; 什么是JVM的语言无关性&#xff1f; 什么是JVM的解释执行 什么是JIT? JIT&#xff1a;在Java编程语言和环境中&#xff0c;即时编译器&#xff08;JIT compiler&#xff0c;just-in-time compiler&#xff09;是一个把Java的字节码&#xff08;…

Fireworks AI和MongoDB:依托您的数据,借助优质模型,助力您开发高速AI应用

我们欣然宣布 MongoDB与 Fireworks AI 正携手合作 让客户能够利用生成式人工智能 (AI) 更快速、更高效、更安全地开展创新活动 Fireworks AI由 Meta旗下 PyTorch团队的行业资深人士于 2022 年底创立&#xff0c;他们在团队中主要负责优化性能、提升开发者体验以及大规模运…

Ubuntu22.04有线网络连接但是没网,网络图标显示问号

Ubuntu22.04有线网络连接但是没网&#xff0c;网络图标显示问号 问题描述解决方案 问题描述 有线网络连接 但是没网 且网络图标显示问号 解决方案 进入设置->隐私->在 连接情况 中关闭连接检查 关闭后 网络正常

vue 时间轴页面 自己的写法 欢迎交流指正

<div class"first-box"><!--贯穿线--><div class"vertical-line-wrap"><div class"vertical-line"></div><div class"vertical-line-arrow"></div></div><!--开始--><div c…

用于图生成的自回归扩散模型 笔记

1 Title Autoregressive Diffusion Model for Graph Generation&#xff08;Lingkai Kong、Jiaming Cui、Haotian Sun、Yuchen Zhuang、B. Aditya Prakash、Chao Zhang&#xff09;【PMLR 2022】 2 Conclusion This study propose an autoregressive diffusion model …

iOS ------ JSONModel源码

一&#xff0c;JSONModel的基本使用 1&#xff0c;基本使用方法 - (instancetype)initWithDictionary:(NSDictionary *)dict error:(NSError **)err; - (instancetype)initWithData:(NSData *)data error:(NSError **)error; - (instancetype)initWithString:(NSString *)str…

Python深度学习基于Tensorflow(3)Tensorflow 构建模型

文章目录 数据导入和数据可视化数据集制作以及预处理模型结构低阶 API 构建模型中阶 API 构建模型高阶 API 构建模型保存和导入模型 这里以实际项目CIFAR-10为例&#xff0c;分别使用低阶&#xff0c;中阶&#xff0c;高阶 API 搭建模型。 这里以CIFAR-10为数据集&#xff0c;C…

9.4.k8s的控制器资源(job控制器,cronjob控制器)

目录 一、job控制器 二、cronjob控制器 一、job控制器 job控制器就是一次性任务的pod控制器&#xff0c;pod完成作业后不会重启&#xff0c;其重启策略是&#xff1a;Never&#xff1b; 简单案例 启动一个pod&#xff0c;执行完成一个事件&#xff0c;然后pod关闭&#xff1b;…

初识指针(2)<C语言>

前言 前文介绍完了一些指针基本概念&#xff0c;下面介绍一下&#xff0c;const关键字、指针的运算、野指针的成因以及避免&#xff0c;assert函数等。 目录 const&#xff08;常属性&#xff09; 变量的常属性 指针的常属性 指针的运算 ①指针 -整数 ②指针-指针 ③指针与…

【Osek网络管理测试】[TG3_TC6]等待总线睡眠状态_2

&#x1f64b;‍♂️ 【Osek网络管理测试】系列&#x1f481;‍♂️点击跳转 文章目录 1.环境搭建2.测试目的3.测试步骤4.预期结果5.测试结果 1.环境搭建 硬件&#xff1a;VN1630 软件&#xff1a;CANoe 2.测试目的 验证DUT在满足进入等待睡眠状态的条件时是否进入该状态 …

17 内核开发-内核内部内联汇编学习

​ 17 内核开发-内核内部内联汇编学习 课程简介&#xff1a; Linux内核开发入门是一门旨在帮助学习者从最基本的知识开始学习Linux内核开发的入门课程。该课程旨在为对Linux内核开发感兴趣的初学者提供一个扎实的基础&#xff0c;让他们能够理解和参与到Linux内核的开发过程中…

英伟达推出视觉语言模型:VILA

NVIDIA和MIT的研究人员推出了一种新的视觉语言模型(VLM)预训练框架&#xff0c;名为VILA。这个框架旨在通过有效的嵌入对齐和动态神经网络架构&#xff0c;改进语言模型的视觉和文本的学习能力。VILA通过在大规模数据集如Coy0-700m上进行预训练&#xff0c;采用基于LLaVA模型的…

VBA编程之条件语句

上一篇我们讲述了条件语句以及分支。文章的最后用到了逻辑运算符“And“那么今天我们来聊一聊逻辑运算符和Select……Case结构。 在学习前我们先来了解一下&#xff0c;在生活中我们经常说”这个包括那个“&#xff0c;”你或者他“&#xff0c;”不是“等等。而这里”包括“和…

esp32+mqtt协议+paltformio+vscode+微信小程序+温湿度检测

花费两天时间完成了这个项目&#xff08;不完全是&#xff0c;属于是在resnet模型训练和温湿度检测两头跑......模型跑不出来&#xff0c;又是第一次从头到尾独立玩硬件&#xff0c;属于是焦头烂额了......&#xff0c;完成这个项目后&#xff0c;我的第一反应是写个csdn&#…

[每日AI·0506]巴菲特谈 AI,李飞飞创业,苹果或将推出 AI 功能,ChatGPT 版搜索引擎

AI 资讯 苹果或将推出 AI 功能&#xff0c;随 iPhone 发布2024 年巴菲特股东大会&#xff0c;巴菲特将 AI 类比为核技术 巴菲特股东大会 5 万字实录消息称 OpenAI 将于 5 月 9 日发布 ChatGPT 版搜索引擎路透社消息&#xff0c;斯坦福大学 AI 领军人物李飞飞打造“空间智能”创…

论文辅助笔记:Tempo 之 model.py

0 导入库 import math from dataclasses import dataclass, asdictimport torch import torch.nn as nnfrom src.modules.transformer import Block from src.modules.prompt import Prompt from src.modules.utils import (FlattenHead,PoolingHead,RevIN, )1TEMPOConfig 1.…

【C++】 认识多态 + 多态的构成条件详细讲解

前言 C 目录 1. 多态的概念2 多态的定义及实现2 .1 虚函数&#xff1a;2 .2 虚函数的重写&#xff1a;2 .2.1 虚函数重写的两个例外&#xff1a; 2 .3 多态的两个条件&#xff08;重点&#xff09;2 .4 析构函数为啥写成虚函数 3 新增的两个关键字3.1 final的使用&#xff1a;3…