iOS中GCD的使用小結

來源:互聯網
上載者:User

iOS中GCD的使用小結

多線程相關概念多線程編程技術的優缺點比較?GCD中的三種隊列類型The main queue(主線程串列隊列)Global queue(全域並發隊列)Custom queue (自訂隊列)Group queue (隊列組)GCD中一些系統提供的常用dispatch方法

多線程相關概念進程與線程 進程概念: 進程是程式在電腦上的一次執行活動,開啟一個app,就開啟了一個進程,可包含多個線程。線程概念: 獨立執行的程式碼片段,一個線程同時間只能執行一個任務,反之多線程並發就可以在同一時間執行多個任務。iOS程式中,主線程(又叫作UI線程)主要任務是處理UI事件,顯示和重新整理UI,(只有主線程有直接修改UI的能力)耗時的操作放在子線程(又叫作後台線程、非同步線程)。在iOS中開子線程去處理耗時的操作,可以有效提高程式的執行效率,提高資源使用率。但是開啟線程會佔用一定的記憶體,(主線程的堆棧大小是1M,第二個線程開始都是512KB,並且該值不能通過編譯器開關或線程API函數來更改)降低程式的效能。所以一般不要同時開很多線程。 線程相關 同步線程:同步線程會阻塞當前線程去執行線程內的任務,執行完之後才會反回當前線程。非同步線程:非同步線程不會阻塞當前線程,會開啟其他線程去執行線程內的任務。串列隊列:線程任務按先後順序逐個執行(需要等待隊列裡面前面的任務執行完之後再執行新的任務)。並發隊列:多個任務按添加順序一起開始執行(不用等待前面的任務執行完再執行新的任務),但是添加間隔往往忽略不計,所以看著像是一起執行的。並發VS並行:並行是基於多核裝置的,並行一定是並發,並發不一定是並行。 多線程中會出現的問題 Critical Section(臨界程式碼片段)
指的是不能同時被兩個線程訪問的程式碼片段,比如一個變數,被並發進程訪問後可能會改變變數值,造成資料汙染(資料共用問題)。Race Condition (競態條件)
當多個線程同時訪問共用的資料時,會發生爭用情形,第一個線程讀取改變了一個變數的值,第二個線程也讀取改變了這個變數的值,兩個線程同時操作了該變數,此時他們會發生競爭來看哪個線程會最後寫入這個變數,最後被寫入的值將會被保留下來。Deadlock (死結)
兩個(多個)線程都要等待對方完成某個操作才能進行下一步,這時就會發生死結。Thread Safe(安全執行緒)
一段安全執行緒的代碼(對象),可以同時被多個線程或並發的任務調度,不會產生問題,非安全執行緒的只能按次序被訪問。所有Mutable對象都是非安全執行緒的,所有Immutable對象都是安全執行緒的,使用Mutable對象,一定要用同步鎖來同步訪問(@synchronized)。互斥鎖:能夠防止多線程搶奪造成的資料安全問題,但是需要消耗大量的資源原子屬性(atomic)加鎖 atomic: 原子屬性,為setter方法加鎖,將屬性以atomic的形式來聲明,該屬性變數就能支援互斥鎖了。nonatomic: 非原子屬性,不會為setter方法加鎖,聲明為該屬性的變數,用戶端應盡量避免多線程爭奪同一資源。 Context Switch (環境切換)
當一個進程中有多個線程來回切換時,context switch用來記錄執行狀態,這樣的進程和一般的多線程進程沒有太大差別,但會產生一些額外的開銷。多線程編程技術的優缺點比較NSThread (抽象層次:低) 優點:輕量級,簡單易用,可以直接操作線程對象缺點: 需要自己管理線程的生命週期,線程同步。線程同步對資料的加鎖會有一定的系統開銷。 Cocoa NSOperation (抽象層次:中) 優點:不需要關心線程管理,資料同步的事情,可以把精力放在學要執行的操作上。基於GCD,是對GCD 的封裝,比GCD更加物件導向缺點: NSOperation是個抽象類別,使用它必須使用它的子類,可以實現它或者使用它定義好的兩個子類NSInvocationOperation、NSBlockOperation.

GCD 全稱Grand Center Dispatch (抽象層次:高)

優點:是 Apple 開發的一個多核編程的解決方案,簡單易用,效率高,速度快,基於C語言,更底層更高效,並且不是Cocoa架構的一部分,自動管理線程生命週期(建立線程、調度任務、銷毀線程)。

缺點: 使用GCD的情境如果很複雜,就有非常大的可能遇到死結問題。

GCD抽象層次最高,使用也簡單,因此,蘋果也推薦使用GCD

GCD中的三種隊列類型

 

GCD編程的核心就是dispatch隊列,dispatch block的執行最終都會放進某個隊列中去進行。

 

The main queue(主線程串列隊列): 與主線程功能相同,提交至Main queue的任務會在主線程中執行, Main queue 可以通過dispatch_get_main_queue()來擷取。 Global queue(全域並發隊列): 全域並發隊列由整個進程共用,有高、中(預設)、低、後台四個優先順序別。 Global queue 可以通過調用dispatch_get_global_queue函數來擷取(可以設定優先權) Custom queue (自訂隊列): 可以為串列,也可以為並發。 Custom queue 可以通過dispatch_queue_create()來擷取; Group queue (隊列組):將多線程進行分組,最大的好處是可獲知所有線程的完成情況。 Group queue 可以通過調用dispatch_group_create()來擷取,通過dispatch_group_notify,可以直接監聽組裡所有線程完成情況。

 

gcd中相關函數的使用一般都是以dispatch開頭

 

The main queue(主線程串列隊列)

 

dispatch_sync 同步執行任務函數,不會開啟新的線程,dispatch_async 非同步執行任務函數,會開啟新的線程

 

擷取主線程串列隊列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
主線程串列隊列同步執行任務,在主線程運行時,會產生死結
dispatch_queue_t mainQueue = dispatch_get_main_queue();dispatch_sync(mainQueue,^{NSLog("MainQueue");            });
程式一直處於等待狀態,block中的代碼將執行不到主線程串列隊列非同步執行任務,在主線程運行,不會產生死結。
dispatch_queue_t mainQueue = dispatch_get_main_queue();dispatch_async(mainQueue,^{NSLog("MainQueue");            });
程式正常運行,block中的代碼正常運行從子線程,非同步返回主線程更新UI<這種使用方式比較多>
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_async(globalQueue, ^{    //子線程非同步執行下載任務,防止主線程卡頓    NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];    NSError *error;    NSString *htmlData = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];    if (htmlData != nil) {        dispatch_queue_t mainQueue = dispatch_get_main_queue();         //非同步返回主線程,根據擷取的資料,更新UI        dispatch_async(mainQueue, ^{            NSLog(@"根據更新UI介面");        });    } else {        NSLog(@"error when download:%@",error);    }});
主線程串列隊列由系統預設產生的,所以無法調用dispatch_resume()和dispatch_suspend()來控制執行繼續或中斷。Global queue(全域並發隊列)

 

耗時的操作,比如讀取網路資料,IO,資料庫讀寫等,我們會在另外一個線程中處理這些操作,然後通知主線程更新介面

 

擷取全域並發隊列
//程式預設的隊列層級,一般不要修改,DISPATCH_QUEUE_PRIORITY_DEFAULT == 0dispatch_queue_t globalQueue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//HIGHdispatch_queue_t globalQueue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);//LOWdispatch_queue_t globalQueue3 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);//BACKGROUNDdispatch_queue_t globalQueue4 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
全域並發隊列同步執行任務,在主線程執行會導致頁面卡頓。
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);NSLog(@"current task");dispatch_sync(globalQueue, ^{    sleep(2.0);    NSLog(@"sleep 2.0s");});NSLog(@"next task");
控制台輸出如下:
2015-11-18 15:51:45.550 Whisper[33152:345023] current task2015-11-18 15:51:47.552 Whisper[33152:345023] sleep 2.0s2015-11-18 15:51:47.552 Whisper[33152:345023] next task
2s鐘之後,才會執行block程式碼片段下面的代碼。全域並發隊列非同步執行任務,在主線程運行,會開啟新的子線程去執行任務,頁面不會卡頓。
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);NSLog(@"current task");dispatch_async(globalQueue, ^{    sleep(2.0);    NSLog(@"sleep 2.0s");});NSLog(@"next task");
控制台輸出如下:
2015-11-18 15:50:14.999 Whisper[33073:343781] current task2015-11-18 15:50:15.000 Whisper[33073:343781] next task2015-11-18 15:50:17.004 Whisper[33073:343841] sleep 2.0s
主線程不用等待2s鐘,繼續執行block程式碼片段後面的代碼。
多個全域並發隊列,非同步執行任務。
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);NSLog(@"current task");dispatch_async(globalQueue, ^{    NSLog(@"最先加入全域並發隊列");});dispatch_async(globalQueue, ^{    NSLog(@"次加入全域並發隊列");});NSLog(@"next task");
控制台輸出如下:
2015-11-18 16:54:52.202 Whisper[39827:403208] current task2015-11-18 16:54:52.203 Whisper[39827:403208] next task2015-11-18 16:54:52.205 Whisper[39827:403309] 最先加入全域並發隊列2015-11-18 16:54:52.205 Whisper[39827:403291] 次加入全域並發隊列
非同步線程的執行順序是不確定的。幾乎同步開始執行
全域並發隊列由系統預設產生的,所以無法調用dispatch_resume()和dispatch_suspend()來控制執行繼續或中斷。Custom queue (自訂隊列)

自訂串列隊列

擷取自訂串列隊列

dispatch_queue_t serialQueue = dispatch_queue_create("com.dullgrass.serialQueue", DISPATCH_QUEUE_SERIAL);NSLog(@"%s",dispatch_queue_get_label(conCurrentQueue)) ;

控制台輸出:

2015-11-19 11:05:34.469 Whisper[1223:42960] com.dullgrass.serialQueue

dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)函數中第一個參數是給這個queue起的標識,這個在調試的可以看到是哪個隊列在執行,或者在crash日誌中,也能做為提示。第二個是需要建立的隊列類型,是串列的還是並發的

自訂串列隊列同步執行任務

dispatch_queue_t serialQueue = dispatch_queue_create("com.dullgrass.serialQueue", DISPATCH_QUEUE_SERIAL);NSLog(@"current task");dispatch_sync(serialQueue, ^{NSLog(@"最先加入自訂串列隊列");sleep(2);});dispatch_sync(serialQueue, ^{NSLog(@"次加入自訂串列隊列");});NSLog(@"next task");

控制台輸出:

2015-11-18 17:09:40.025 Whisper[40241:416296] current task2015-11-18 17:09:40.027 Whisper[40241:416296] 最先加入自訂串列隊列2015-11-18 17:09:43.027 Whisper[40241:416296] 次加入自訂串列隊列2015-11-18 17:09:43.027 Whisper[40241:416296] next task

當前線程等待串列隊列中的子線程執行完成之後再執行,串列隊列中先進來的子線程先執行任務,執行完成後,再執行隊列中後面的任務。

自訂串列隊列嵌套執行同步任務,產生死結

dispatch_queue_t serialQueue = dispatch_queue_create("com.dullgrass.serialQueue", DISPATCH_QUEUE_SERIAL);dispatch_sync(serialQueue, ^{   //該程式碼片段後面的代碼都不會執行,程式被鎖定在這裡NSLog(@"會執行的代碼");dispatch_sync(serialQueue, ^{   NSLog(@"代碼不執行");});});

非同步執行串列隊列,嵌套同步執行串列隊列,同步執行的串列隊列中的任務將不會被執行,其他程式正常執行

dispatch_queue_t serialQueue = dispatch_queue_create("com.dullgrass.serialQueue", DISPATCH_QUEUE_SERIAL);dispatch_async(serialQueue, ^{NSLog(@"會執行的代碼");dispatch_sync(serialQueue, ^{   NSLog(@"代碼不執行");});});

 

注意不要嵌套使用同步執行的串列隊列任務

 

自訂並發隊列

擷取自訂並發隊列
dispatch_queue_t conCurrentQueue =   dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);
自訂並發隊列執行同步任務
dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);NSLog(@"current task");dispatch_sync(conCurrentQueue, ^{   NSLog(@"先排入佇列");});dispatch_sync(conCurrentQueue, ^{   NSLog(@"次排入佇列");});NSLog(@"next task");
控制台輸出如下:
2015-11-19 10:36:23.259 Whisper[827:20596] current task2015-11-19 10:36:23.261 Whisper[827:20596] 先排入佇列2015-11-19 10:36:23.261 Whisper[827:20596] 次排入佇列2015-11-19 10:36:23.261 Whisper[827:20596] next task
自訂並發隊列嵌套執行同步任務(不會產生死結,程式正常運行)
dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);NSLog(@"current task");dispatch_sync(conCurrentQueue, ^{     NSLog(@"先排入佇列");     dispatch_sync(conCurrentQueue, ^{         NSLog(@"次排入佇列");     });});NSLog(@"next task");
控制台輸出如下:
2015-11-19 10:39:21.301 Whisper[898:22273] current task2015-11-19 10:39:21.303 Whisper[898:22273] 先排入佇列2015-11-19 10:39:21.303 Whisper[898:22273] 次排入佇列2015-11-19 10:39:21.303 Whisper[898:22273] next task
自訂並發隊列執行非同步任務
dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);NSLog(@"current task");dispatch_async(conCurrentQueue, ^{   NSLog(@"先排入佇列");});dispatch_async(conCurrentQueue, ^{   NSLog(@"次排入佇列");});NSLog(@"next task");
控制台輸出如下:
2015-11-19 10:45:22.290 Whisper[1050:26445] current task2015-11-19 10:45:22.290 Whisper[1050:26445] next task2015-11-19 10:45:22.290 Whisper[1050:26505] 次排入佇列2015-11-19 10:45:22.290 Whisper[1050:26500] 先排入佇列

非同步執行任務,開啟新的子線程,不影響當前線程任務的執行,並發隊列中的任務,幾乎是同步執行的,輸出順序不確定

Group queue (隊列組)

當遇到需要執行多個線程並發執行,然後等多個線程都結束之後,再匯總執行結果時可以用group queue

使用情境: 同時下載多個圖片,所有圖片下載完成之後去更新UI(需要回到主線程)或者去處理其他任務(可以是其他線程隊列)。原理:使用函數dispatch_group_create建立dispatch group,然後使用函數dispatch_group_async來將要執行的block任務提交到一個dispatch queue。同時將他們添加到一個組,等要執行的block任務全部執行完成之後,使用dispatch_group_notify函數接收完成時的訊息。

使用樣本:

dispatch_queue_t conCurrentGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_queue_t mainQueue = dispatch_get_main_queue();dispatch_group_t groupQueue = dispatch_group_create();NSLog(@"current task");dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{   NSLog(@"並行任務1");});dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{   NSLog(@"並行任務2");});dispatch_group_notify(groupQueue, mainQueue, ^{   NSLog(@"groupQueue中的任務 都執行完成,回到主線程更新UI");});NSLog(@"next task");

控制台輸出:

2015-11-19 13:47:55.117 Whisper[1645:97116] current task2015-11-19 13:47:55.117 Whisper[1645:97116] next task2015-11-19 13:47:55.119 Whisper[1645:97178] 並行任務12015-11-19 13:47:55.119 Whisper[1645:97227] 並行任務22015-11-19 13:47:55.171 Whisper[1645:97116] groupQueue中的任務 都執行完成,回到主線程更新UI

在當前線程阻塞的同步等待dispatch_group_wait

dispatch_group_t groupQueue = dispatch_group_create();dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC);dispatch_queue_t conCurrentGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);NSLog(@"current task");dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{   long isExecuteOver = dispatch_group_wait(groupQueue, delayTime);   if (isExecuteOver) {       NSLog(@"wait over");   } else {       NSLog(@"not over");   }   NSLog(@"並行任務1");});dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{   NSLog(@"並行任務2");});

控制台輸出如下:

2015-11-19 14:37:29.514 Whisper[2426:126683] current task2015-11-19 14:37:29.518 Whisper[2426:126791] 並行任務22015-11-19 14:37:39.515 Whisper[2426:126733] wait over2015-11-19 14:37:39.516 Whisper[2426:126733] 並行任務1

dispatch_time(dispatch_time_t when, int64_t delta);
參數注釋:
第一個參數一般是DISPATCH_TIME_NOW,表示從現在開始
第二個參數是延時的具體時間
延時1秒可以寫成如下幾種:
NSEC_PER_SEC----每秒有多少納秒
dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC);
USEC_PER_SEC----每秒有多少毫秒(注意是指在納秒的基礎上)
dispatch_time(DISPATCH_TIME_NOW, 1000*USEC_PER_SEC); //SEC---毫秒
NSEC_PER_USEC----每毫秒有多少納秒。
dispatch_time(DISPATCH_TIME_NOW, USEC_PER_SEC*NSEC_PER_USEC);SEC---納秒

GCD中一些系統提供的常用dispatch方法

dispatch_after延時添加到隊列

使用樣本:
dispatch_time_t delayTime3 = dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC);dispatch_time_t delayTime2 = dispatch_time(DISPATCH_TIME_NOW, 2*NSEC_PER_SEC);dispatch_queue_t mainQueue = dispatch_get_main_queue();NSLog(@"current task");dispatch_after(delayTime3, mainQueue, ^{  NSLog(@"3秒之後添加到隊列");});dispatch_after(delayTime2, mainQueue, ^{   NSLog(@"2秒之後添加到隊列");});NSLog(@"next task");
控制台輸出如下:
2015-11-19 15:50:19.369 Whisper[2725:172593] current task2015-11-19 15:50:19.370 Whisper[2725:172593] next task2015-11-19 15:50:21.369 Whisper[2725:172593] 2秒之後添加到隊列2015-11-19 15:50:22.654 Whisper[2725:172593] 3秒之後添加到隊列

dispatch_after只是延時提交block,並不是延時後立即執行,並不能做到精確控制,需要精確控制的朋友慎用哦

dispatch_apply在給定的隊列上多次執行某一任務,在主線程直接調用會阻塞主線程去執行block中的任務。

dispatch_apply函數的功能:把一項任務提交到隊列中多次執行,隊列可以是串列也可以是並行,dispatch_apply不會立刻返回,在執行完block中的任務後才會返回,是同步執行的函數。dispatch_apply正確使用方法:為了不阻塞主線程,一般把dispatch_apply放在非同步隊列中調用,然後執行完成後通知主線程使用樣本:
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);NSLog(@"current task");dispatch_async(globalQueue, ^{dispatch_queue_t applyQueue = dispatch_get_global_queue(0, 0);//第一個參數,3--block執行的次數//第二個參數,applyQueue--block任務提交到的隊列//第三個參數,block--需要重複執行的任務dispatch_apply(3, applyQueue, ^(size_t index) {      NSLog(@"current index %@",@(index));      sleep(1);});NSLog(@"dispatch_apply 執行完成");dispatch_queue_t mainQueue = dispatch_get_main_queue();dispatch_async(mainQueue, ^{      NSLog(@"回到主線程更新UI");});});NSLog(@"next task");
控制台輸出如下:
2015-11-19 16:24:45.015 Whisper[4034:202269] current task2015-11-19 16:24:45.016 Whisper[4034:202269] next task2015-11-19 16:24:45.016 Whisper[4034:202347] current index 02015-11-19 16:24:45.016 Whisper[4034:202344] current index 12015-11-19 16:24:45.016 Whisper[4034:202345] current index 22015-11-19 16:24:46.021 Whisper[4034:202347] dispatch_apply 執行完成2015-11-19 16:24:46.021 Whisper[4034:202269] 回到主線程更新UI
嵌套使用dispatch_apply會導致死結。

dispatch_once保證在app運行期間,block中的代碼只執行一次

經典使用情境---單例單例對象ShareManager的定義:
 ShareManager的.h檔案#import @interface ShareManager : NSObject@property (nonatomic, copy) NSString *someProperty;+ (ShareManager *)shareManager;+ (ShareManager *)sharedManager;@endShareManager的.m檔案#import "ShareManager.h"@implementation ShareManagerstatic ShareManager *sharedManager = nil;//GCD實現單例功能+ (ShareManager *)shareManager{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{     sharedManager = [[self alloc] init]; }); return sharedManager;}//在ARC下,非GCD,實現單例功能+ (ShareManager *)sharedManager{ @synchronized(self) {     if (!sharedManager) {         sharedManager = [[self alloc] init];     } } return sharedManager;}- (instancetype)init{ self = [super init]; if (self) {      _someProperty =@"Default Property Value"; } return self;}@endShareManager的使用#import "ShareManager.h"在需要使用的函數中,直接調用下面的方法ShareManager *share = [ShareManager sharedManager];NSLog(@"share is %@",share.someProperty);
dispatch_barrier_async 柵欄的作用 功能:是在並行隊列中,等待在dispatch_barrier_async之前加入的隊列全部執行完成之後(這些任務是並發執行的)再執行dispatch_barrier_async中的任務,dispatch_barrier_async中的任務執行完成之後,再去執行在dispatch_barrier_async之後加入到隊列中的任務(這些任務是並發執行的)。使用樣本:
dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(conCurrentQueue, ^{  NSLog(@"dispatch 1");});dispatch_async(conCurrentQueue, ^{   NSLog(@"dispatch 2");});dispatch_barrier_async(conCurrentQueue, ^{   NSLog(@"dispatch barrier");});dispatch_async(conCurrentQueue, ^{   NSLog(@"dispatch 3");});dispatch_async(conCurrentQueue, ^{   NSLog(@"dispatch 4");});
控制台輸出如下:
2015-11-19 18:12:34.125 Whisper[22633:297257] dispatch 12015-11-19 18:12:34.125 Whisper[22633:297258] dispatch 22015-11-19 18:12:34.126 Whisper[22633:297258] dispatch barrier2015-11-19 18:12:34.127 Whisper[22633:297258] dispatch 32015-11-19 18:12:34.127 Whisper[22633:297257] dispatch 4

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.