【iOS】鎖[特殊字符]

文章目錄

  • 前言
  • 1??什么是鎖🔒?
    • 1.1 基本概念
    • 1.2 鎖的分類
  • 2??OC 中的常用鎖
    • 2.1 OSSpinLock(已棄用):“自旋鎖”的經典代表
      • 為什么盡量在開發中不使用自旋鎖
        • 自旋鎖的本質缺陷:忙等待(Busy Waiting)
        • os_unfair_lock的局限性:不適用于復雜場景
        • 蘋果的官方建議:優先使用更高效的鎖
    • 2.2 dispatch_semaphore_t(GCD 信號量):“高性能通用鎖”
    • 2.3 pthread_mutex(POSIX 互斥鎖):“最通用的系統級鎖”
    • 2.4 NSLock:“OC 層面的互斥鎖封裝”
    • 2.5 @synchronized:“OC 特有的語法糖”
    • 2.6 NSCondition:“條件等待鎖”(生產者-消費者型)
  • 3??鎖的對比與選擇
  • 4??常見陷阱
    • 4.1 死鎖(Deadlock)
    • 4.2 鎖內執行耗時操作
    • 4.3 錯誤使用鎖對象
  • 總結

前言

??在前段時間學習dyld時,接觸到了鎖,由于并不是很清楚鎖的知識,導致涉及到鎖的其他內容也有點懵懂,再加上,想要深入了解OC中的多線程,鎖是前提預備知識,所以筆者對鎖進行簡單學習并撰寫了這篇博客。

1??什么是鎖🔒?

1.1 基本概念

百度解釋如下:

鎖是編程中用于協調多個線程或進程對共享資源訪問的機制,主要用于防止并發沖突、確保數據一致性和程序正確性。 ?

互斥性?:保證同一時刻只有一個線程/進程訪問共享資源,避免數據競爭。

協調線程/進程的執行順序,確保操作原子性(全部完成或全部不完成)。

簡單來說,鎖就像一個“開關”,在同一時間只允許一個線程“進入”某個代碼段或訪問某個資源,其他線程需要等待,直到鎖被釋放。

1.2 鎖的分類

根據分類標準,一般情況下我們把鎖分為一下7大類別:

(1)悲觀鎖和樂觀鎖

(2)公平鎖和非公平鎖

(3)共享鎖和獨占鎖

(4)可重入鎖和非可重入鎖

(5)自旋鎖和非自旋鎖

(6)偏向鎖、輕量級鎖和重量級鎖

(7)可中斷鎖和不可中斷鎖

在OC中,鎖的大類就兩種自旋鎖和互斥鎖,可以細分為以下幾類:

類型特點典型代表
互斥鎖(Mutex)同一時間僅允許一個線程加鎖,不可重入pthread_mutex、NSLock
自旋鎖線程會反復檢查變量是否可用OSSpinLock(已棄用)、atomic
條件鎖(Condition)等待特定條件滿足后再加鎖NSCondition、pthread_cond_t
遞歸鎖(Recursive Lock)允許同一線程多次加鎖(需對應次數解鎖)pthread_mutex(recursive)、NSRecursiveLock
信號量(Semaphore)控制并發線程數量(非嚴格互斥)dispatch_semaphore_t
語言特性鎖OC 語法糖,簡化鎖操作@synchronized(互斥鎖)

另外還有一個讀寫鎖:讀寫鎖實際是一種特殊的自旋鎖。將對共享資源的訪問分成讀者和寫者,讀者只對共享資源進行讀訪問,寫者則需要對共享資源進行寫操作。這種鎖相對于自旋鎖而言,能提高并發性。
在這里插入圖片描述

2??OC 中的常用鎖

2.1 OSSpinLock(已棄用):“自旋鎖”的經典代表

原理:自旋鎖(Spin Lock)通過忙等待(循環檢查鎖狀態)實現互斥。當鎖被占用時,其他線程不會休眠,而是不斷循環嘗試獲取鎖,直到成功。

歷史:OSSpinLock 曾是 OC 中最快的鎖(無系統調用,純用戶態操作),但因 優先級反轉問題(低優先級線程持有鎖時,高優先級線程會瘋狂自旋搶占 CPU,導致系統卡頓)在 iOS 10 后被棄用。

示例代碼(僅作原理參考,禁止在生產環境使用):

#import <os/lock.h>os_unfair_lock lock = OS_UNFAIR_LOCK_INIT; // OSSpinLock 已棄用,替代方案是 os_unfair_lock(本質是改良的自旋鎖)- (void)threadSafeMethod {os_unfair_lock_lock(&lock);// 臨界區:訪問共享資源os_unfair_lock_unlock(&lock);
}

注意:os_unfair_lock是 OSSpinLock 的替代方案,但仍為自旋鎖,適用于輕量級同步(如單次數據訪問),避免在鎖內執行耗時操作。

為什么盡量在開發中不使用自旋鎖

自旋鎖的本質缺陷:忙等待(Busy Waiting)

os_unfair_lock的底層實現與被棄用的 OSSpinLock類似,均基于自旋鎖機制。當鎖被其他線程占用時,當前線程會進入一個 無限循環(忙等待),不斷檢查鎖是否釋放。這種機制會導致以下問題:

1.cpu資源的浪費

自旋鎖的“忙等待”會持續占用 CPU 時間片,即使線程并未執行任何有效操作。在高負載場景(如多線程競爭激烈)下,大量線程空轉會導致 CPU 使用率飆升,甚至引發系統卡頓。

示例對比:

  • 傳統互斥鎖(如 pthread_mutex):鎖被占用時,線程會主動休眠(釋放 CPU),等待鎖釋放后被喚醒。
  • 自旋鎖(如 os_unfair_lock):鎖被占用時,線程持續空轉,CPU 資源被無意義消耗。

2.優先級反轉

當低優先級的線程持有鎖時,高優先級線程會因不斷嘗試獲取鎖而頻繁搶占cpu,導致低優先級線程無法運行(被“餓死”)。這種現象被稱為優先級反轉,會嚴重破壞系統的實時性和公平性。

eg:低優先級線程 A 持有 os_unfair_lock。高優先級線程 B 嘗試獲取鎖,進入忙等待,持續占用 CPU。系統被迫頻繁調度高優先級線程 B,低優先級線程 A 無法獲得執行機會。

os_unfair_lock的局限性:不適用于復雜場景

盡管 os_unfair_lock比 OSSpinLock更輕量(減少了部分內存屏障),但它的設計目標僅限于 輕量級、短時間的臨界區保護(如單次內存訪問)。對于以下場景,它無法提供可靠支持:

1. 長時間持有鎖的操作

如果臨界區內需要執行耗時操作(如文件 I/O、網絡請求、復雜計算),os_unfair_lock的忙等待會導致線程長時間占用 CPU,嚴重影響其他任務的執行效率。

eg:

// 錯誤用法:臨界區執行耗時操作(如讀取大文件)
os_unfair_lock_lock(&lock);
NSData *largeData = [NSData dataWithContentsOfFile:@"/bigfile.dat"]; // 耗時操作
os_unfair_lock_unlock(&lock);

此時,線程會因忙等待導致 CPU 空轉,而文件讀取的 I/O 操作本身是阻塞的(無需 CPU 參與),造成資源浪費。

2.遞歸鎖需求

os_unfair_lock不支持遞歸加鎖(同一線程無法多次獲取同一把鎖)。如果代碼中存在遞歸調用(如方法 A 調用方法 B,兩者都需要加同一把鎖),會導致死鎖。

eg:

- (void)recursiveMethod {os_unfair_lock_lock(&lock);// 遞歸調用自身[self recursiveMethod]; // 第二次加鎖會失敗,導致死鎖os_unfair_lock_unlock(&lock);
}
蘋果的官方建議:優先使用更高效的鎖

蘋果在官方文檔中明確推薦,避免使用自旋鎖(包括 os_unfair_lock)處理需要長時間持有或高競爭的場景,并提供了更優的替代方案:

1. dispatch_semaphore_t(GCD 信號量)

基于內核信號量實現,鎖被占用時線程會休眠(釋放 CPU),支持并發控制(計數 >1 時允許多線程同時訪問)。適用于輕量級同步、限制并發任務數(如限制同時下載的文件數)等場景。

2. pthread_mutex(POSIX 互斥鎖)

支持遞歸鎖(通過 PTHREAD_MUTEX_RECURSIVE類型),內核級實現,穩定性高。適用于需要遞歸加鎖或多線程頻繁競爭的場景(如嵌套方法調用)。

3. NSLock(OC 層面封裝)

API 簡潔,基于 pthread_mutex實現,支持 tryLock非阻塞加鎖。適用于簡單的線程同步(如保護單次數據訪問)。

2.2 dispatch_semaphore_t(GCD 信號量):“高性能通用鎖”

信號量(Semaphore)是基于計數器的一種多線程同步機制,用來管理對資源的并發訪問。信號量就是一種可用來控制訪問資源的數量的標識,設定了一個信號量,在線程訪問之前,加上信號量的處理,則可告知系統按照我們指定的信號量數量來執行多個線程。

相關函數:

  • dispatch_semaphore_t、dispatch_semaphore_create(long value):創建信號量,初始化計數(通常為 1 時表示互斥鎖)。參數為信號量的初值,小于零就會返回NULL。

  • 線程加鎖時調用 dispatch_semaphore_wait減少計數(若計數為 0 則阻塞)。long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout); :等待降低信號量,接收一個信號和時間值(多為DISPATCH_TIME_FOREVER)。若信號的信號量為0,則會阻塞當前線程,直到信號量大于0或者經過輸入的時間值。若信號量大于0,則會使信號量減1并返回,程序繼續住下執行。

  • 解鎖時調用 dispatch_semaphore_signal增加計數(喚醒等待線程)。long dispatch_semaphore_signal(dispatch_semaphore_t dsema); :提高信號量, 使信號量加1并返回 在dispatch_semaphore_wait和dispatch_semaphore_signal這兩個函數中間的執行代碼,每次只會允許限定數量的線程進入,這樣就有效的保證了在多線程環境下,只能有限定數量的線程進入。

特點

  • 性能接近 OSSpinLock(底層通過內核信號量實現,但比傳統鎖更高效)。
  • 支持控制并發線程數量(計數 >1 時為“并發鎖”,允許指定數量線程同時訪問)。

示例代碼

/*
// 初始化信號量(計數為 1,即互斥鎖)
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);- (void)threadSafeMethod {// 加鎖:計數減 1(若計數為 0 則阻塞當前線程)dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);// 臨界區:訪問共享資源// 解鎖:計數加 1(喚醒等待線程)dispatch_semaphore_signal(semaphore);
}
*///具體實例
#import <Foundation/Foundation.h>
#import <os/lock.h>int main(int argc, const char * argv[]) {@autoreleasepool {// 共享資源:一個需要線程安全的計數器__block int counter = 0;// 初始化信號量(計數為 1,即互斥鎖;若計數>1,允許指定數量線程同時訪問)dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);// 模擬 10 個線程同時修改計數器for (int i = 0; i < 10; i++) {dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{for (int j = 0; j < 1000; j++) {// 加鎖:計數減 1(若計數為 0 則阻塞)dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);// 臨界區:修改共享資源(需保證原子性)counter++;// 解鎖:計數加 1(喚醒等待線程)dispatch_semaphore_signal(semaphore);}});}// 等待所有線程完成后打印結果(實際開發中需用更嚴謹的同步機制)sleep(2);NSLog(@"最終計數器值:%d", counter); // 應輸出 10000(10 線程×1000 次)}return 0;
}

運行測試:

請添加圖片描述

適用場景

  • 需要高性能互斥的場景(如高頻數據讀寫)。
  • 控制并發任務數量(如限制同時下載的任務數,計數設為 3)。

2.3 pthread_mutex(POSIX 互斥鎖):“最通用的系統級鎖”

POSIX 標準的互斥鎖(Mutex),通過內核實現線程阻塞。支持兩種類型:

  • 普通鎖(PTHREAD_MUTEX_INITIALIZER):不可重入,同一線程重復加鎖會死鎖。
  • 遞歸鎖(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP):允許同一線程多次加鎖(需對應次數解鎖)。

示例代碼

/*
#import <pthread.h>// 初始化遞歸鎖(允許同一線程多次加鎖)
pthread_mutex_t recursiveLock;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); // 設置為遞歸鎖
pthread_mutex_init(&recursiveLock, &attr);- (void)recursiveMethod {pthread_mutex_lock(&recursiveLock);// 臨界區(可能遞歸調用自身)pthread_mutex_unlock(&recursiveLock);
}// 銷毀鎖(避免內存泄漏)
pthread_mutex_destroy(&recursiveLock);
pthread_mutexattr_destroy(&attr);
*///具體實例
#import <Foundation/Foundation.h>
#import <os/lock.h>
#import <pthread/pthread.h>int main(int argc, const char * argv[]) {@autoreleasepool {// 共享資源:一個需要線程安全的數組__block NSMutableArray *sharedArray = [NSMutableArray array];// 初始化遞歸鎖(允許同一線程多次加鎖)pthread_mutex_t recursiveLock;pthread_mutexattr_t attr;pthread_mutexattr_init(&attr);pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); // 關鍵:設置為遞歸鎖pthread_mutex_init(&recursiveLock, &attr);// 線程 1:嵌套調用方法dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{pthread_mutex_lock(&recursiveLock); // 第一次加鎖[sharedArray addObject:@"A"];// 嵌套調用(需再次加鎖)pthread_mutex_lock(&recursiveLock); // 第二次加鎖(遞歸鎖允許)[sharedArray addObject:@"B"];pthread_mutex_unlock(&recursiveLock); // 第一次解鎖pthread_mutex_unlock(&recursiveLock); // 第二次解鎖});// 線程 2:直接訪問共享資源dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{pthread_mutex_lock(&recursiveLock);[sharedArray addObject:@"C"];pthread_mutex_unlock(&recursiveLock);});// 等待線程完成后打印結果sleep(2);NSLog(@"共享數組:%@", sharedArray); // 應輸出 ["A", "B", "C"](順序可能不同)}return 0;
}

運行測試:

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

特點

  • 性能穩定,兼容所有 iOS 版本。
  • 遞歸鎖適合嵌套調用場景(如方法 A 調用方法 B,兩者都需要加同一把鎖)。

2.4 NSLock:“OC 層面的互斥鎖封裝”

原理:NSLock是 pthread_mutex的 OC 封裝,提供了更簡潔的 API(如 lock、unlock、tryLock)。默認是普通鎖(不可重入),但可通過 NSRecursiveLock子類實現遞歸鎖。

示例代碼

/*
// 普通互斥鎖
NSLock *lock = [[NSLock alloc] init];- (void)threadSafeMethod {[lock lock];// 臨界區[lock unlock];
}// 嘗試加鎖(非阻塞,返回 BOOL 表示是否成功)
if ([lock tryLock]) {// 臨界區[lock unlock];
}// 遞歸鎖(允許同一線程多次加鎖)
NSRecursiveLock *recursiveLock = [[NSRecursiveLock alloc] init];
*///具體實例
#import <Foundation/Foundation.h>
#import <os/lock.h>
#import <pthread/pthread.h>int main(int argc, const char * argv[]) {@autoreleasepool {// 共享資源:一個需要線程安全的用戶信息字典__block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];// 初始化普通互斥鎖NSLock *lock = [[NSLock alloc] init];// 創建一個調度組dispatch_group_t group = dispatch_group_create();// 線程 1:修改用戶信息dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{[lock lock]; // 加鎖userInfo[@"name"] = @"張三";userInfo[@"age"] = @25;[lock unlock]; // 解鎖});// 線程 2:讀取用戶信息(需等待線程 1 解鎖)dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{[lock lock]; // 加鎖(若線程 1 未解鎖會阻塞)NSString *name = userInfo[@"name"];NSNumber *age = userInfo[@"age"];NSLog(@"用戶信息:%@,%@", name, age); // 應輸出 "張三",25[lock unlock]; // 解鎖});// 等待所有異步任務完成dispatch_group_wait(group, DISPATCH_TIME_FOREVER);}return 0;
}

運行測試:

請添加圖片描述

注意:NSLock的 unlock必須與 lock成對出現,否則可能導致死鎖(如異常未捕獲導致 unlock未執行)。

2.5 @synchronized:“OC 特有的語法糖”

原理:@synchronized是 OC 編譯器提供的語法糖,底層通過哈希表將鎖對象映射到內核互斥鎖。語法簡潔,無需手動管理鎖的創建和銷毀。

示例代碼

// 以某個對象(如 self)為鎖的標識
- (void)threadSafeMethod {@synchronized (self) { // 鎖對象為 self// 臨界區:訪問共享資源}
}// 也可以用其他對象作為鎖(推薦專用鎖對象,避免與其他代碼沖突)
NSObject *lockObj = [[NSObject alloc] init];
@synchronized (lockObj) {// 臨界區
}

特點

  • 代碼簡潔,無需手動加鎖/解鎖(自動管理)。
  • 鎖對象需唯一(不同鎖對象無法同步)。
  • 性能較差(底層涉及哈希表查找和內核調用),適合小范圍同步(如單次數據訪問)。

2.6 NSCondition:“條件等待鎖”(生產者-消費者型)

原理NSConditionpthread_cond_t的 OC 封裝,結合了互斥鎖和條件變量。允許線程在條件不滿足時等待(釋放鎖并休眠),條件滿足時被喚醒(重新加鎖)。

示例代碼(生產者-消費者模型):

@interface ProducerConsumer : NSObject {NSMutableArray *_queue;NSCondition *_condition;NSInteger _maxCount;
}
@end@implementation ProducerConsumer
- (instancetype)init {if (self = [super init]) {_queue = [NSMutableArray array];_condition = [[NSCondition alloc] init];_maxCount = 10; // 隊列最大容量}return self;
}// 生產者:添加數據(隊列滿時等待)
- (void)produce {[_condition lock];while (_queue.count >= _maxCount) {[_condition wait]; // 條件不滿足,釋放鎖并休眠}[_queue addObject:@(arc4random_uniform(100))];[_condition signal]; // 喚醒一個等待的消費者[_condition unlock];
}// 消費者:取出數據(隊列空時等待)
- (void)consume {[_condition lock];while (_queue.count == 0) {[_condition wait]; // 條件不滿足,釋放鎖并休眠}id obj = _queue.firstObject;[_queue removeObjectAtIndex:0];[_condition signal]; // 喚醒一個等待的生產者[_condition unlock];
}
@end

適用場景:需要線程間協調(如“生產者-消費者”模型),等待特定條件滿足后再執行。

3??鎖的對比與選擇

OC 中常見鎖的性能(從高到低,單線程加鎖/解鎖耗時):

os_unfair_lock ≈ dispatch_semaphore_t > pthread_mutex(遞歸) > NSRecursiveLock > NSLock > @synchronized

鎖的選擇:

  1. 性能要求高:優先選 dispatch_semaphore_t(通用)或 os_unfair_lock(輕量同步)。
  2. 需要遞歸:選 pthread_mutex(recursive)NSRecursiveLock
  3. 代碼簡潔性:選 @synchronized(適合小范圍同步)。
  4. 條件等待:選 NSCondition(如生產者-消費者模型)。

4??常見陷阱

4.1 死鎖(Deadlock)

原因:多個線程互相等待對方釋放鎖(如線程 A 持有鎖 1 等待鎖 2,線程 B 持有鎖 2 等待鎖 1)。

解決

  • 避免嵌套加鎖(如非必要不使用遞歸鎖)。
  • 統一加鎖順序(所有線程按相同順序獲取鎖)。

4.2 鎖內執行耗時操作

原因:鎖的加鎖/解鎖涉及內核調用,若臨界區內執行耗時操作(如 IO、大量計算),會導致其他線程長時間等待,降低并發效率。

解決

  • 將耗時操作移到鎖外(如先讀取數據到臨時變量,再在鎖內處理)。

4.3 錯誤使用鎖對象

原因@synchronized使用動態對象(如可能被釋放的 self)作為鎖標識,或不同線程使用不同的鎖對象。

解決

  • @synchronized的鎖對象需是生命周期穩定的(如專用 NSObject實例)。

總結

OC 中的鎖機制需根據場景選擇:

  • 輕量同步dispatch_semaphore_tos_unfair_lock(性能最優)。
  • 遞歸需求pthread_mutex(recursive)NSRecursiveLock
  • 代碼簡潔@synchronized(小范圍使用)。
  • 條件協調NSCondition(如生產者-消費者)。

核心原則:鎖的范圍盡可能小(僅保護臨界區),避免死鎖,優先使用系統提供的高性能鎖(如 GCD 信號量)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/92525.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/92525.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/92525.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在easyui中如何設置自帶的彈窗,有輸入框

這個就是帶input的確認彈框&#xff08;$.messager.prompt&#xff09;// 使用prompt并添加placeholder提示 $.messager.prompt(確認, 確定要將事故記錄標記為 statusText 嗎&#xff1f;, function(r) {if (r) {// r 包含用戶輸入的內容var remark r.trim();// 驗證輸入不為…

Android-API調用學習總結

一、Postman檢查API接口是否支持1.“HTTP Request” 來創建一個新的請求。——請求構建界面&#xff0c;這是你進行所有 API 調用的地方。2.設置請求方法和 URL&#xff1a;選擇請求方法&#xff1a; 在 URL 輸入框左側&#xff0c;有一個下拉菜單。點擊它&#xff0c;選擇你想…

《計算機網絡》實驗報告一 常用網絡命令

目 錄 1、實驗目的 2、實驗環境 3、實驗內容 3.1 ping基本用法 3.2 ifconfig/ipconfig基本用法 3.3 traceroute/tracert基本用法 3.4 arp基本用法 3.5 netstat基本用法 4、實驗結果與分析 4.1 ping命令的基本用法 4.2 ifconfig/ipconfig命令的基本用法 4.3 tracer…

MySQL深度理解-深入理解MySQL索引底層數據結構與算法

1.引言在項目中會遇到各種各樣的慢查詢的問題&#xff0c;對于千萬級的表&#xff0c;如果使用比較笨的查詢方式&#xff0c;查詢一條SQL可能需要幾秒甚至幾十秒&#xff0c;如果將索引設置的比較合理&#xff0c;可以將查詢變得仍然非常快。2.索引的本質索引&#xff1a;幫助M…

Django母嬰商城項目實踐(九)- 商品列表頁模塊

9、商品列表頁模塊 1、業務邏輯 商品模塊分為:商品列表頁 和 商品詳情頁 商品列表頁將所有商品按照一定的規則排序展示,用于可以從銷量、價格、上架時間和收藏數量設置商品的排序方式,并且在商品左側設置分類列表,選擇某一個分類可以篩選出對應的商品信息。 商品列表頁…

8、STM32每個系列的區別

1、F1和F4的系列的區別 F1采用Crotex M3內核&#xff0c;F4采用Crotex M4內核。F4比F1的主頻高。F4具有浮點數運算單元&#xff0c;F1沒有浮點單元。F4的具備增強的DSP指令集。F407的執行16位DSP指令的時間只有F1的30%~70%。F4執行32位DSP指令的時間只有F1的25% ~ 60%。F1內部S…

DeepSPV:一種從2D超聲圖像中估算3D脾臟體積的深度學習流程|文獻速遞-醫學影像算法文獻分享

Title題目DeepSPV: A deep learning pipeline for 3D spleen volume estimation from 2Dultrasound imagesDeepSPV&#xff1a;一種從2D超聲圖像中估算3D脾臟體積的深度學習流程01文獻速遞介紹1.1 臨床背景 脾腫大指脾臟增大&#xff0c;是多種潛在疾病的重要臨床指標&#x…

病歷數智化3分鐘:AI重構醫院數據價值鏈

一、方案概述本方案針對某省醫聯體醫院病例數據管理需求&#xff0c;通過AI技術實現病歷數字化→信息結構化→數據應用化的全流程改造。系統采用雙端協同架構&#xff1a; - 普通用戶端&#xff1a;為一線醫護人員提供病歷拍攝、AI識別修正、安全上傳功能 - 管理員后臺&#…

CSS+JavaScript 禁用瀏覽器復制功能的幾種方法

&#x1f6e1;? 禁用瀏覽器復制功能完整指南 網頁中禁用用戶的復制功能&#xff0c;包括 CSS 方法、JavaScript 方法、綜合解決方案以及實際應用場景。適用于需要保護內容版權、防止惡意爬取或提升用戶體驗的場景。 &#x1f4cb; 目錄 &#x1f680; 快速開始&#x1f3a8…

Java 虛擬線程在高并發微服務中的實戰經驗分享

Java 虛擬線程在高并發微服務中的實戰經驗分享 虛擬線程&#xff08;Virtual Threads&#xff09;作為Java 19引入的預覽特性&#xff0c;為我們在高并發微服務場景下提供了一種更輕量、易用的并發模型。本文結合真實生產環境&#xff0c;講述在Spring Boot微服務中引入和使用虛…

《拆解WebRTC:NAT穿透的探測邏輯與中繼方案》

WebRTC以其無需插件的便捷性&#xff0c;成為連接全球用戶的隱形橋梁。但很少有人知曉&#xff0c;每一次流暢的視頻對話背后&#xff0c;都藏著一場與網絡邊界的無聲博弈——NAT&#xff0c;這個為緩解IPv4地址枯竭而生的技術&#xff0c;既是網絡安全的屏障&#xff0c;也是端…

前端開發 React 組件優化

1. 使用 React.memo 進行組件優化問題&#xff1a;當父組件重新渲染時&#xff0c;子組件也會重新渲染&#xff0c;即使它的 props 沒有變化。解決方案&#xff1a;使用 React.memo 包裹子組件&#xff0c;讓其只在 props 變化時才重新渲染。示例場景&#xff1a;展示一個顯示計…

變頻器實習DAY12

目錄變頻器實習DAY12一、繼續&#xff0c;柔性平臺測試&#xff01;上午 王工Modbus新功能測試下午 柔性平臺繼續按照說明書再測一遍附加的小知識點中國貍花貓.git文件附學習參考網址歡迎大家有問題評論交流 (* ^ ω ^)變頻器實習DAY12 一、繼續&#xff0c;柔性平臺測試&…

Redis--多路復用

&#x1f9e9; 一、什么是“客戶端連接”&#xff1f;所謂 客戶端連接 Redis&#xff0c;指的是&#xff1a;一個程序&#xff08;客戶端&#xff09;通過網絡連接到 Redis 服務端&#xff08;比如 127.0.0.1:6379&#xff09;&#xff0c;建立一個 TCP 連接&#xff0c;雙方可…

數組——初識數據結構

一維數組數組的創建數組是一種相同類型元素的集合數組的創建方式C99 中引入了變長數組的概念&#xff0c;變長數組支持數組的大小使用變量來指定明顯這里的vs2019不支持變長數組數組初始化和不完全初始化第二個數組就是典型的不完全初始化&#xff0c;開辟了10個空間&#xff0…

技術速遞|使用 Semantic Kernel 與 A2A 協議構建多智能體解決方案

作者&#xff1a;盧建暉 - 微軟高級云技術布道師 翻譯/排版&#xff1a;Alan Wang 在快速發展的 AI 應用開發領域&#xff0c;能夠協調多個智能體已成為構建復雜企業級解決方案的關鍵。雖然單個 AI 智能體擅長特定任務&#xff0c;但復雜的業務場景往往需要跨平臺、跨框架甚至跨…

前端跨域請求原理及實踐

在前端開發中&#xff0c;"跨域"是一個繞不開的話題。當我們的頁面嘗試從一個域名請求另一個域名的資源時&#xff0c;瀏覽器往往會拋出類似Access to fetch at xxx from origin xxx has been blocked by CORS policy的錯誤。下面將深入探討跨域請求的底層原理&#…

SpringBoot07-數據層的解決方案:SQL

一、內置數據源 1-1、【回顧】Druid數據源的配置 druid的兩種導入格式 1-2、springboot提供的3種內置數據源的配置 若是不配置Druid&#xff0c; springboot提供了3中默認的數據源配置&#xff0c;它們分別是&#xff1a; 1. HikariCP&#xff08;默認&#xff09; 從 Spring…

前端自動化埋點:頁面模塊級行為跟蹤與問題定位系統??的技術設計方案

一、核心設計目標??精細化監控??&#xff1a;定位到頁面中??單個模塊??的曝光、點擊等行為。??低侵入性??&#xff1a;業務代碼與埋點邏輯解耦&#xff0c;降低開發維護成本。??鏈路可追蹤??&#xff1a;串聯用戶從曝光到操作的完整行為路徑。??實時性??&a…

Node.js 與 Java 性能對比

一、核心架構與任務模型對比Node.js 單線程事件循環 非阻塞I/O 通過V8引擎執行JavaScript&#xff0c;采用事件驅動模型&#xff0c;所有I/O操作&#xff08;如網絡請求、文件讀寫&#xff09;均為非阻塞。單線程處理所有請求&#xff0c;但通過事件循環&#xff08;Event Loo…