多線程 并沒(méi)有那么難

串行并行的定義

串行:一個(gè)線程中執(zhí)行多個(gè)任務(wù),只能一個(gè)一個(gè)的按照順序執(zhí)行這些任務(wù)灿意。
并行:一個(gè)進(jìn)程中可以開(kāi)啟多條線程缤剧,每條線程可以同時(shí)執(zhí)行不同的任務(wù)

多線程的原理

同一時(shí)間,cpu只能處理1條線程汗销,只有1條線程在工作,如果存在多條線程弛针,實(shí)際上是線程間以非常非诚髯拢快的速度進(jìn)行切換,CPU調(diào)度線程的速度非澄看裕快瘾杭,看起來(lái)就像同時(shí)進(jìn)行。需要注意的是睬隶,線程不宜太多苏潜,會(huì)消耗大量CPU資源

優(yōu)點(diǎn)

能適當(dāng)提高程序的執(zhí)行效率变勇,適當(dāng)?shù)奶岣逤PU和內(nèi)存利用率
缺點(diǎn):創(chuàng)建線程是有開(kāi)銷的,線程的創(chuàng)建需要90毫秒的時(shí)間飞袋,如果大量的開(kāi)啟線程巧鸭,會(huì)降低程序的性能麻捻,而且線程越多,程序越復(fù)雜郑叠,比如線程之間的通信乡革,多線程的數(shù)據(jù)共享

安全隱患

  • 資源共享
    一塊資源可以被多個(gè)線程同時(shí)訪問(wèn)(例如,3個(gè)線程同時(shí)修改一個(gè)文件)
    解決方案:加同步鎖 @synchronized(鎖對(duì)象){需要鎖定的代碼 }
    多個(gè)線程之間鎖對(duì)象必須是同一個(gè)沸版,保證線程之間用的鎖是同一個(gè),否則鎖是無(wú)效的心包,一般用self就可以
    使用前提:多條線程搶奪同一塊資源的時(shí)候,需要對(duì)數(shù)據(jù)訪問(wèn)修改等問(wèn)題時(shí)
@synchronized (self) {
        // 要鎖定的操作
        NSLog(@"%@", [NSThread currentThread]);
    }
  • 原子和非原子屬性
    atomic:原子屬性区宇,setter方法加鎖值戳,調(diào)用setter方法前加鎖,調(diào)用之后鎖打開(kāi)卧晓,防止多條線程對(duì)屬性值的修改逼裆,會(huì)消耗大量的資源
    nonatomic:非原子屬性赦政,適合內(nèi)存小的移動(dòng)設(shè)備,setter方法和getter方法大部分都在主線程訪問(wèn)桐愉,如有在子線程訪問(wèn)的从诲,可單獨(dú)加鎖靡羡,在寫代碼的過(guò)程中盡量避免多線程搶奪同一塊資源

線程間通信

包括線程間數(shù)據(jù)傳遞、在一個(gè)線程中執(zhí)行完特定任務(wù)后跳轉(zhuǎn)到其他線程繼續(xù)執(zhí)行任務(wù)

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    _picView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
    [self.view addSubview:_picView];
    
    // 創(chuàng)建線程
    [self performSelectorInBackground:@selector(downLoadPic) withObject:nil];
 
}

- (void)downLoadPic
{
    NSURL *url = [NSURL URLWithString:@""];
    
    NSData *data = [NSData dataWithContentsOfURL:url];
    
    UIImage *pic = [UIImage imageWithData:data];
    
    // 回主線程
//    [_picView performSelectorOnMainThread:@selector(setPicView:) withObject:pic waitUntilDone:YES];
    
    [_picView performSelector:@selector(setPicView:) onThread:[NSThread mainThread] withObject:pic waitUntilDone:YES];
}

線程實(shí)現(xiàn)方法

1.pthread

基于C語(yǔ)言,需要手動(dòng)管理纳像,平時(shí)幾乎不用

先導(dǎo)入頭文件#import <pthread.h>

// 指向函數(shù)的指針
void *run(void *param)
{
    return NULL;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    pthread_t thread;
    pthread_create(&thread, NULL, run, NULL);
}

2.NSThread

基于OC, 需要手動(dòng)管理,常用的就幾個(gè)方法

+(NSThread *)mainThread; // 獲取主線程
+(BOOL)isMainThread; // 是否為主線程
-(BOOL)isMainThread; // 是否為主線程
+(NSThread *)currentThread; // 獲取當(dāng)前線程
-(void)setName:(NSString *)name; // 設(shè)置線程名字
-(NSString *)name; // 獲取線程名字
+(void)sleepUntilDate:(NSDate *)date; // 休眠到什么時(shí)間
+(void)sleepForTimeInterval:(NSTimeInterval)ti; // 休眠幾秒鐘
+(void)exit; // 退出當(dāng)前線程憔购,停止了就不能恢復(fù)了

三種創(chuàng)建方法如下

- (void)run
{
    // 打印當(dāng)前線程
    NSLog(@"%@", [NSThread currentThread]);
}

- (void)createThread1
{
    // 創(chuàng)建線程
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:@"louise"];
    // 啟動(dòng)線程
    [thread start];
}

- (void)createThread2
{
    // 不需要啟動(dòng)玫鸟,沒(méi)有返回值,拿不到剛剛創(chuàng)建的線程妥曲,所以不能設(shè)置名字檐盟,用來(lái)處理簡(jiǎn)單的操作
    [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:@"louise"];
}

- (void)createThread3
{
    // 隱式創(chuàng)建,看不出來(lái)是創(chuàng)建線程
    [self performSelectorInBackground:@selector(run) withObject:@"louise"]; 
}

3.GCD

  • 優(yōu)勢(shì):自動(dòng)管理線程的生命周期(創(chuàng)建葵萎,任務(wù)的調(diào)度,銷毀線程)
    核心概念:任務(wù)(執(zhí)行什么操作)羡忘、隊(duì)列(用來(lái)存放任務(wù))

  • 執(zhí)行任務(wù):
    同步:只能在當(dāng)前線程中執(zhí)行任務(wù)卷雕,不具備開(kāi)啟新線程的能力:dispatch_sync
    異步:可以在新的線程中執(zhí)行任務(wù)爽蝴,具備開(kāi)啟新線程的能力:dispatch_async

  • 隊(duì)列的類型
    并發(fā)隊(duì)列:可以讓多個(gè)任務(wù)并發(fā)執(zhí)行纫骑,并發(fā)功能只能在異步(dispatch_async)函數(shù)下才有效
    串行隊(duì)列:讓任務(wù)一個(gè)接著一個(gè)的執(zhí)行

  • 區(qū)分幾個(gè)比較容易混淆的詞語(yǔ)
    同步和異步:在于能否開(kāi)啟新的線程先馆,同步只能在當(dāng)前線程執(zhí)行任務(wù),不具備開(kāi)線程的能力梅惯,異步可以在新的線程中執(zhí)行任務(wù)仿野,具備開(kāi)線程的能力

    并發(fā)和串行:并發(fā)是多個(gè)任務(wù)并發(fā)執(zhí)行脚作,串行是一個(gè)任務(wù)接一個(gè)任務(wù)的執(zhí)行

  • 并發(fā)/串行隊(duì)列&同步/異步代碼實(shí)現(xiàn)

    
    // label相當(dāng)于隊(duì)列的名字
    // DISPATCH_QUEUE_CONCURRENT 并發(fā)隊(duì)列
    // DISPATCH_QUEUE_SERIAL 串行隊(duì)列

    // 1.創(chuàng)建一個(gè)串行隊(duì)列
    // dispatch_queue_t queue = dispatch_queue_create("serial_chuan", DISPATCH_QUEUE_SERIAL);
    // 1.創(chuàng)建一個(gè)并發(fā)隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("concurrent_bing", DISPATCH_QUEUE_CONCURRENT);
    
    // 2.將任務(wù)同步加入隊(duì)列
    // dispatch_sync(queue, ^{
        
        // 要執(zhí)行的代碼
    //    NSLog(@"1----%@", [NSThread currentThread]);
    // });
    // dispatch_sync(queue, ^{
        
        // 要執(zhí)行的代碼
     //   NSLog(@"2----%@", [NSThread currentThread]);
    // });

    // 2.將任務(wù)異步加入隊(duì)列
    dispatch_async(queue, ^{
        
        // 要執(zhí)行的代碼
        NSLog(@"1----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        
        // 要執(zhí)行的代碼
        NSLog(@"2----%@", [NSThread currentThread]);
    });
  • GCD其他常用函數(shù)
    • 延時(shí)操作
      除了NSObject的performSelector和NSTimer之外還可以使用GCD的方法 dispatch_after(dispatch_time_t when, dispatch_queue_t queue, ^(void)block)

        // 2.0 * NSEC_PER_SEC:兩秒之后執(zhí)行
        // dispatch_queue_t queue:在哪個(gè)隊(duì)列里執(zhí)行
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        // 兩秒后執(zhí)行這里的代碼
    });
  • 一次性代碼
    整個(gè)程序運(yùn)行過(guò)程中只調(diào)用一次劣针,不是每個(gè)對(duì)象各調(diào)用一次,這里需要注意
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        // 整個(gè)程序運(yùn)行過(guò)程中只調(diào)用一次
    });
  • 快速迭代
    同時(shí)遍歷所有的數(shù)據(jù) dispatch_apply(size_t iterations, dispatch_queue_t queue, ^(size_t)block)
    dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
        
        // 同時(shí)遍歷10個(gè)數(shù)據(jù),比如剪切復(fù)制粘貼等 是不需要順序的鸟廓,可以同時(shí)進(jìn)行操作
        NSLog(@"----%zu-----%@", index, [NSThread currentThread]);
    });

4.NSOperationQueue

通過(guò)NSOperation 和NSOperationQueue配合實(shí)現(xiàn)多線程

  • 優(yōu)點(diǎn):不需要管理線程的創(chuàng)建和調(diào)用引谜,只要注重執(zhí)行的操作即可

  • 原理:將操作封裝到NSOperation對(duì)象中擎浴,然后將NSOperation對(duì)象添加到NSOperationQueue隊(duì)列中退客,系統(tǒng)會(huì)自動(dòng)將任務(wù)取出放到線程中執(zhí)行

  • NSOperation的子類:NSOperation是個(gè)抽象類,使用它必須用它的子類: NSInvocationOperation链嘀,NSBlockOperation怀泊,自定義繼承自NSOperation的子類.

  • NSOperation的代碼實(shí)現(xiàn)

- (void)InvocationOperation
{

    // 在當(dāng)前線程執(zhí)行,只有將任務(wù)添加到隊(duì)列中才會(huì)開(kāi)新線程
//    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
//    [op start];
    
 }

- (void)BlockOperation
{

    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        
        // 在當(dāng)前線程執(zhí)行
        NSLog(@"1----%@",[NSThread currentThread]);
    }];
    
    // 添加額外的任務(wù)务傲,在子線程執(zhí)行
    [op addExecutionBlock:^{
        
        NSLog(@"2----%@",[NSThread currentThread]);
    }];
    [op addExecutionBlock:^{
        
        NSLog(@"3----%@",[NSThread currentThread]);
    }];
    
    [op start];

 }

}

- (void)run
{
    NSLog(@"%@",[NSThread currentThread]);
}

  • NSOperationQueue的代碼實(shí)現(xiàn) - 串行

// 默認(rèn)的都是串行隊(duì)列
- (void)NSOperationQueue
{

    // 創(chuàng)建隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    // 創(chuàng)建NSInvocationOperation任務(wù)
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
    NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
    
    // 只要將任務(wù)添加到隊(duì)列售葡,就新開(kāi)啟線程挟伙,并且不需要調(diào)用start方法
    [queue addOperation:op1];
    [queue addOperation:op2];
    
    // 創(chuàng)建NSBlockOperation任務(wù)
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"3----%@",[NSThread currentThread]);
    }];
     // 還可再添加額外的任務(wù)尖阔,在子線程執(zhí)行
    [op3 addExecutionBlock:^{
    
        NSLog(@"3-----1----%@",[NSThread currentThread]);
    }];

    // 只要添加到隊(duì)列中介却,就新開(kāi)線程
    [queue addOperation:op3];
    
}

- (void)run
{
    NSLog(@"%@",[NSThread currentThread]);
}

當(dāng)異步執(zhí)行的代碼特別多特別長(zhǎng)的時(shí)候就使用自定義NSOperation块茁,可以將任務(wù)封裝起來(lái),使用的時(shí)候只需要調(diào)用自定義類的alloc init方法轴或,然后把任務(wù)添加到隊(duì)列中即可

  • NSOperationQueue的代碼實(shí)現(xiàn) - 并行
    只要設(shè)置最大并發(fā)數(shù)不為1就是并行

- (void)NSOperationQueue
{
    // 創(chuàng)建隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    // 設(shè)置最大并發(fā)操作數(shù)仰禀,如果設(shè)置最大并發(fā)數(shù)為1,就是串行隊(duì)列
    queue.maxConcurrentOperationCount = 3;
    
    // 創(chuàng)建NSBlockOperation任務(wù)
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"1----%@",[NSThread currentThread]);
    }];
    // 只要添加到隊(duì)列中饺蚊,就新開(kāi)線程
    [queue addOperation:op1];
    
    // 也可以不創(chuàng)建NSOperation 直接創(chuàng)建任務(wù)
    [queue addOperationWithBlock:^{
        
        NSLog(@"2-------%@", [NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        
        NSLog(@"3-------%@", [NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        
        NSLog(@"4-------%@", [NSThread currentThread]);
    }];
}

  • 線程的暫停
    需要注意的是悬嗓,暫停是等當(dāng)前的任務(wù)執(zhí)行完成之后暫停后面的任務(wù)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.suspended = YES;
  • 取消線程任務(wù)
    任務(wù)取消了之后不可恢復(fù)污呼,同樣的,也是等當(dāng)前的任務(wù)執(zhí)行完成之后在取消
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue cancelAllOperations];
  • 線程間依賴
- (void)addDependency
{

    // 創(chuàng)建隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    // 創(chuàng)建NSBlockOperation任務(wù)
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"1----%@",[NSThread currentThread]);
    }];
    
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"2----%@",[NSThread currentThread]);
    }];

    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"3----%@",[NSThread currentThread]);
    }];

    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"4----%@",[NSThread currentThread]);
    }];
    
    // 設(shè)置依賴,op3依賴于op1和op2包竹,需要op1和op2都執(zhí)行完才能執(zhí)行op3
    [op3 addDependency:op1];
    [op3 addDependency:op2];

    [queue addOperation:op1];
    [queue addOperation:op2];
    [queue addOperation:op3];
    [queue addOperation:op4];
    
}

需要注意的是燕酷,可以跨隊(duì)列依賴,但是不能互相依賴(A依賴B,B依賴A)

  • 線程間通信
    // 創(chuàng)建隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    // 創(chuàng)建NSBlockOperation任務(wù)
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        
        // 開(kāi)子線程
        NSLog(@"1----%@",[NSThread currentThread]);
        
        
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            
            // 回到主線程
        }];
        
        
    }];
    
    [queue addOperation:op1];

到這里多線程基本上就介紹完了周瞎,是不是很簡(jiǎn)單呢苗缩,多多實(shí)踐就會(huì)發(fā)現(xiàn)真的很簡(jiǎn)單,有什么問(wèn)題可以私信我喲声诸,如果喜歡酱讶,感覺(jué)對(duì)你有點(diǎn)幫助,可以點(diǎn)個(gè)關(guān)注喲O(∩_∩)O哈哈

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市灶挟,隨后出現(xiàn)的幾起案子膏萧,更是在濱河造成了極大的恐慌,老刑警劉巖曹锨,帶你破解...
    沈念sama閱讀 222,865評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件齐鲤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡捧灰,警方通過(guò)查閱死者的電腦和手機(jī)炭庙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)腻脏,“玉大人,你說(shuō)我怎么就攤上這事腐碱。” “怎么了殃饿?”我有些...
    開(kāi)封第一講書人閱讀 169,631評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵帖池,是天一觀的道長(zhǎng)肴甸。 經(jīng)常有香客問(wèn)我原在,道長(zhǎng)村怪,這世上最難降的妖魔是什么甚负? 我笑而不...
    開(kāi)封第一講書人閱讀 60,199評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮碰辅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘循衰。我一直安慰自己,他們只是感情好迁酸,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,196評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般儿惫。 火紅的嫁衣襯著肌膚如雪留搔。 梳的紋絲不亂的頭發(fā)上函喉,一...
    開(kāi)封第一講書人閱讀 52,793評(píng)論 1 314
  • 那天哺窄,我揣著相機(jī)與錄音坷襟,去河邊找鬼婴程。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蒸绩,可吹牛的內(nèi)容都是我干的传蹈。 我是一名探鬼主播惦界,決...
    沈念sama閱讀 41,221評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼恕齐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼仪或!你這毒婦竟也來(lái)了范删?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 40,174評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后煤率,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,699評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,770評(píng)論 3 343
  • 正文 我和宋清朗相戀三年鹃彻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欢摄。...
    茶點(diǎn)故事閱讀 40,918評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绿淋,死狀恐怖盾沫,靈堂內(nèi)的尸體忽然破棺而出凸舵,到底是詐尸還是另有隱情,我是刑警寧澤菇夸,帶...
    沈念sama閱讀 36,573評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站羞芍,受9級(jí)特大地震影響纱注,放射性物質(zhì)發(fā)生泄漏刻获。R本人自食惡果不足惜佑颇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,255評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望茬贵。 院中可真熱鬧老充,春花似錦胶背、人聲如沸廷粒。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,749評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春腺劣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,862評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工同云, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,364評(píng)論 3 379
  • 正文 我出身青樓释液,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,926評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • NSThread 第一種:通過(guò)NSThread的對(duì)象方法 NSThread *thread = [[NSThrea...
    攻城獅GG閱讀 805評(píng)論 0 3
  • 歡迎大家指出文章中需要改正或者需要補(bǔ)充的地方涣达,我會(huì)及時(shí)更新棕叫,非常感謝疗认。 一. 多線程基礎(chǔ) 1. 進(jìn)程 進(jìn)程是指在系...
    xx_cc閱讀 7,198評(píng)論 11 70
  • 在這篇文章中扎拣,我將為你整理一下 iOS 開(kāi)發(fā)中幾種多線程方案,以及其使用方法和注意事項(xiàng)。當(dāng)然也會(huì)給出幾種多線程的案...
    張戰(zhàn)威ican閱讀 603評(píng)論 0 0
  • Summary What Is Argument? What is an argument? We may reg...
    讀者_(dá)在路上閱讀 268評(píng)論 0 0
  • sklearn內(nèi)部集成了一些手寫體數(shù)字圖片數(shù)據(jù)集袭异,現(xiàn)在我們使用這些數(shù)據(jù),用SVM支持向量機(jī)算法進(jìn)行訓(xùn)練識(shí)別...
    lzp12138閱讀 2,091評(píng)論 0 6