Linux--線程

Linux線程概念

1 什么是線程

? 在?個程序?的?個執?路線就叫做線程(thread)。更準確的定義是:線程是“?個進程內部
的控制序列”
? ?切進程?少都有?個執?線程
? 線程在進程內部運?,本質是在進程地址空間內運?
? 在Linux系統中,在CPU眼中,看到的PCB都要?傳統的進程更加輕量化
? 透過進程虛擬地址空間,可以看到進程的?部分資源,將進程資源合理分配給每個執?流,就形
成了線程執?流

2 分?式存儲管理

2-1 虛擬地址和?表的由來

思考?下,如果在沒有虛擬內存和分?機制的情況下,每?個??程序在物理內存上所對應的空間必
須是連續的,如下圖:
因為每?個程序的代碼、數據?度都是不?樣的,按照這樣的映射?式,物理內存將會被分割成各種
離散的、??不同的塊。經過?段運?時間之后,有些程序會退出,那么它們占據的物理內存空間可
比特就業課
以被回收,導致這些物理內存都是以很多碎?的形式存在。
怎么辦呢?我們希望操作系統提供給??的空間必須是連續的,但是物理內存最好不要連續。此時虛
擬內存和分?便出現了,如下圖所?:
把物理內存按照?個固定的?度的?框進?分割,有時叫做物理?。每個?框包含?個物理?
(page)。?個?的??等于?框的??。?多數 32位 體系結構?持 4KB 的?,? 64位 體系結
構?般會?持 8KB 的?。區分??和?個?框是很重要的:
? ?框是?個存儲區域;
? ??是?個數據塊,可以存放在任何?框或磁盤中。
有了這種機制,CPU 便并?是直接訪問物理內存地址,?是通過虛擬地址空間來間接的訪問物理內存
地址。所謂的虛擬地址空間,是操作系統為每?個正在執?的進程分配的?個邏輯地址,在32位機
上,其范圍從0 ~ 4G-1。
操作系統通過將虛擬地址空間和物理內存地址之間建?映射關系,也就是?表,這張表上記錄了每?
對?和?框的映射關系,能讓CPU間接的訪問物理內存地址。
總結?下,其思想是將虛擬內存下的邏輯地址空間分為若??,將物理內存空間分為若??框,通過
?表便能把連續的虛擬內存,映射到若?個不連續的物理內存?。這樣就解決了使?連續的物理內存
造成的碎?問題。
1-2-2 物理內存管理
假設?個可?的物理內存有 4GB 的空間。按照?個?框的?? 4KB 進?劃分, 4GB 的空間就是
4GB/4KB = 1048576 個?框。有這么多的物理?,操作系統肯定是要將其管理起來的,操作系統
需要知道哪些?正在被使?,哪些?空閑等等。
內核? struct page 結構表?系統中的每個物理?,出于節省內存的考慮, struct page 中使
?了?量的聯合體union。

/* include/linux/mm_types.h */
struct page {
/* 原?標志,有些情況下會異步更新 */unsigned long flags;
union {
struct {
/* 換出?列表,例如由zone->lru_lock保護的active_list */
struct list_head lru;
/* 如果最低為為0,則指向inode
* address_space,或為NULL
* 如果?映射為匿名內存,最低為置位
* ?且該指針指向anon_vma對象
*/
struct address_space* mapping;
/* 在映射內的偏移量 */
pgoff_t index;
/*
* 由映射私有,不透明數據
* 如果設置了PagePrivate,通常?于buffer_heads
* 如果設置了PageSwapCache,則?于swp_entry_t
* 如果設置了PG_buddy,則?于表?伙伴系統中的階
*/
unsigned long private;
};
struct { /* slab, slob and slub */
union {
struct list_head slab_list; /* uses lru */
struct { /* Partial pages */
struct page* next;
#ifdef CONFIG_64BIT
int pages; /* Nr of pages left */
int pobjects; /* Approximate count */
#else
short int pages;
short int pobjects;
#endif
};
};
struct kmem_cache* slab_cache; /* not slob */
/* Double-word boundary */
void* freelist; /* first free object */
union {
void* s_mem; /* slab: first object */
unsigned long counters; /* SLUB */
struct { /* SLUB */
unsigned inuse : 16; /* ?于SLUB分配器:對象的數? */
unsigned objects : 15;
unsigned frozen : 1;
};
};};
...
};
union {
/* 內存管理?系統中映射的?表項計數,?于表??是否已經映射,還?于限制逆向映射搜
索*/
atomic_t _mapcount;
unsigned int page_type;
unsigned int active; /* SLAB */
int units; /* SLOB */
};
...
#if defined(WANT_PAGE_VIRTUAL)
/* 內核虛擬地址(如果沒有映射則為NULL,即?端內存) */
void* virtual;
#endif /* WANT_PAGE_VIRTUAL */
...
}

**其中?較重要的?個參數:

  1. flags :?來存放?的狀態。這些狀態包括?是不是臟的,是不是被鎖定在內存中等。flag的
    每?位單獨表??種狀態,所以它?少可以同時表?出32種不同的狀態。這些標志定義在
    <linux/page-flags.h>中。其中?些?特位?常重要,如PG_locked?于指定?是否鎖定,
    PG_uptodate?于表??的數據已經從塊設備讀取并且沒有出現錯誤。
  2. _mapcount :表?在?表中有多少項指向該?,也就是這??被引?了多少次。當計數值變
    為-1時,就說明當前內核并沒有引?這??,于是在新的分配中就可以使?它。
  3. virtual :是?的虛擬地址。通常情況下,它就是?在虛擬內存中的地址。有些內存(即所謂
    的?端內存)并不永久地映射到內核地址空間上。在這種情況下,這個域的值為NULL,需要的
    時候,必須動態地映射這些?。
    要注意的是 struct page 與物理?相關,?并?與虛擬?相關。?系統中的每個物理?都要分配?
    個這樣的結構體,讓我們來算算對所有這些?都這么做,到底要消耗掉多少內存。
    算 struct page 占40個字節的內存吧,假定系統的物理?為 4KB ??,系統有 4GB 物理內存。
    那么系統中共有?? 1048576 個(1兆個),所以描述這么多??的page結構體消耗的內存只不過
    40MB ,相對系統 4GB 內存??,僅是很?的?部分罷了。因此,要管理系統中這么多物理??,這
    個代價并不算太?。
    要知道的是,?的??對于內存利?和系統開銷來說?常重要,?太?,? 必然會剩余較?不能利
    ?的空間(?內碎?)。?太?,雖然可以減??內碎?的??,但是?太多,會使得?表太??占
    ?內存,同時系統頻繁地進??轉化,加重系統開銷。因此,?的??應該適中,通常為 512B -
    8KB ,windows系統的?框??為4KB。**

2-3 ?表

?表中的每?個表項,指向?個物理?的開始地址。在 32 位系統中,虛擬內存的最?空間是 4GB ,
這是每?個??程序都擁有的虛擬內存空間。既然需要讓 4GB 的虛擬內存全部可?,那么?表中就需
要能夠表?這所有的 4GB 空間,那么就?共需要 4GB/4KB = 1048576 個表項。如下圖所?:
虛擬內存看上去被虛線“分割”成?個個單元,其實并不是真的分割,虛擬內存仍然是連續的。這個
虛線的單元僅僅表?它與?表中每?個表項的映射關系,并最終映射到相同??的?個物理內存?
上。
?表中的物理地址,與物理內存之間,是隨機的映射關系,哪?可?就指向哪?(物理?)。雖然最終使
?的物理內存是離散的,但是與虛擬內存對應的線性地址是連續的。處理器在訪問數據、獲取指令
時,使?的都是線性地址,只要它是連續的就可以了,最終都能夠通過?表找到實際的物理地址。
在 32 位系統中,地址的?度是 4 個字節,那么?表中的每?個表項就是占? 4 個字節。所以?表占
據的總空間??就是: 1048576*4 = 4MB 的??。也就是說映射表??本?,就要占? 4MB /
4KB = 1024 個物理?。這會存在哪些問題呢?
? 回想?下,當初為什么使??表,就是要將進程劃分為?個個?可以不?連續的存放在物理內存
中,但是此時?表就需要1024個連續的?框,似乎和當時的?標有點背道?馳了…
? 此外,根據局部性原理可知,很多時候進程在?段時間內只需要訪問某?個?就可以正常運?
了。因此也沒有必要?次讓所有的物理?都常駐內存。
解決需要?容量?表的最好?法是:把?表看成普通的?件,對它進?離散分配,即對?表再分?,
由此形成多級?表的思想。
為了解決這個問題,可以把這個單??表拆分成 1024 個體積更?的映射表。如下圖所?。這樣?
來,1024(每個表中的表項個數) * 1024(表的個數),仍然可以覆蓋 4GB 的物理內存空間。
這?的每?個表,就是真正的?表,所以?共有 1024 個?表。?個?表??占? 4KB ,那么
1024 個?表?共就占?了 4MB 的物理內存空間,和之前沒差別啊?
從總數上看是這樣,但是?個應?程序是不可能完全使?全部的 4GB 空間的,也許只要??個?表就
可以了。例如:?個??程序的代碼段、數據段、棧段,?共就需要 10 MB 的空間,那么使? 3 個
?表就?夠了。
計算過程:
每?個?表項指向?個 4KB 的物理?,那么?個?表中 1024 個?表項,?共能覆蓋 4MB 的物理內
存;
那么 10MB 的程序,向上對?取整之后(4MB 的倍數,就是 12 MB),就需要 3 個?表就可以了。

2-4 ??錄結構

到?前為?,每?個?框都被?個?表中的?個表項來指向了,那么這 1024 個?表也需要被管理起
來。管理?表的表稱之為??錄表,形成?級?表。如下圖所?:
? 所有?表的物理地址被??錄表項指向
? ??錄的物理地址被 CR3 寄存器 指向,這個寄存器中,保存了當前正在執?任務的??錄地
址。
所以操作系統在加載??程序的時候,不僅僅需要為程序內容來分配物理內存,還需要為?來保存程
序的??錄和?表分配物理內存。

2-5 兩級?表的地址轉換

**下?以?個邏輯地址為例。將邏輯地址( 0000000000,0000000001,11111111111 )轉換為物
理地址的過程:

  1. 在32位處理器中,采?4KB的???,則虛擬地址中低12位為?偏移,剩下?20位給?表,分成
    兩級,每個級別占10個bit(10+10)。
  2. CR3 寄存器 讀取??錄起始地址,再根據?級?號查??錄表,找到下?級?表在物理內存中
    存放位置。
  3. 根據?級?號查表,找到最終想要訪問的內存塊號。
  4. 結合?內偏移量得到物理地址。
    比特就業課
  5. 注:?個物理?的地址?定是 4KB 對?的(最后的 12 位全部為 0 ),所以其實只需要記錄物理
    ?地址的? 20 位即可。
  6. 以上其實就是 MMU 的?作流程。MMU(Memory Manage Unit)是?種硬件電路,其速度很快,
    主要?作是進?內存管理,地址轉換只是它承接的業務之?。
    到這?其實還有個問題,MMU要先進?兩次?表查詢確定物理地址,在確認了權限等問題后,MMU再將這個物理地址發送到總線,內存收到之后開始讀取對應地址的數據并返回。那么當?表變為N級時,就變成了N次檢索+1次讀寫。可?,?表級數越多查詢的步驟越多,對于CPU來說等待時間越?,效率越低。讓我們現在總結?下:單級?表對連續內存要求?,于是引?了多級?表,但是多級?表也是?把雙刃劍,在減少連續存儲要求且減少存儲空間的同時降低了查詢效率。
    有沒有提升效率的辦法呢?計算機科學中的所有問題,都可以通過添加?個中間層來解決。 MMU 引?了新武器,江湖?稱快表的 TLB (其實,就是緩存)
    當 CPU 給 MMU 傳新虛擬地址之后, MMU 先去問 TLB 那邊有沒有,如果有就直接拿到物理地址發到總線給內存,?活。但 TLB 容量?較?,難免發? Cache Miss ,這時候 MMU 還有保底的?武器
    ?表,在?表中找到之后 MMU 除了把地址發到總線傳給內存,還把這條映射關系給到TLB,讓它記錄?下刷新緩存。**

2-6 缺?異常

設想,CPU 給 MMU 的虛擬地址,在 TLB 和?表都沒有找到對應的物理?,該怎么辦呢?其實這就是
缺?異常 Page Fault ,它是?個由硬件中斷觸發的可以由軟件邏輯糾正的錯誤。
假如?標內存?在物理內存中沒有對應的物理?或者存在但?對應權限,CPU 就?法獲取數據,這種
情況下CPU就會報告?個缺?錯誤。
由于 CPU 沒有數據就?法進?計算,CPU罷?了??進程也就出現了缺?中斷,進程會從??態切換
到內核態,并將缺?中斷交給內核的 Page Fault Handler 處理。
缺?中斷會交給 PageFaultHandler 處理,其根據缺?中斷的不同類型會進?不同的處理:
? Hard Page Fault 也被稱為 Major Page Fault ,翻譯為硬缺?錯誤/主要缺?錯誤,這
時物理內存中沒有對應的物理?,需要CPU打開磁盤設備讀取到物理內存中,再讓MMU建?虛擬
地址和物理地址的映射。
? Soft Page Fault 也被稱為 Minor Page Fault ,翻譯為軟缺?錯誤/次要缺?錯誤,這
時物理內存中是存在對應物理?的,只不過可能是其他進程調?的,發出缺?異常的進程不知道
?已,此時MMU只需要建?映射即可,?需從磁盤讀取寫?內存,?般出現在多進程共享內存區
域。
? Invalid Page Fault 翻譯為?效缺?錯誤,?如進程訪問的內存地址越界訪問,??如對
空指針解引?內核就會報 segment fault 錯誤中斷進程直接掛掉。

3 線程的優點

? 創建?個新線程的代價要?創建?個新進程?得多
? 與進程之間的切換相?,線程之間的切換需要操作系統做的?作要少很多
? 最主要的區別是線程的切換虛擬內存空間依然是相同的,但是進程切換是不同的。這兩種上
下?切換的處理都是通過操作系統內核來完成的。內核的這種切換過程伴隨的最顯著的性能
損耗是將寄存器中的內容切換出。
? 另外?個隱藏的損耗是上下?的切換會擾亂處理器的緩存機制。簡單的說,?旦去切換上下
?,處理器中所有已經緩存的內存地址?瞬間都作廢了。還有?個顯著的區別是當你改變虛
擬內存空間的時候,處理的?表緩沖 TLB (快表)會被全部刷新,這將導致內存的訪問在?
段時間內相當的低效。但是在線程的切換中,不會出現這個問題,當然還有硬件cache。
? 線程占?的資源要?進程少很
? 能充分利?多處理器的可并?數量
? 在等待慢速I/O操作結束的同時,程序可執?其他的計算任務
? 計算密集型應?,為了能在多處理器系統上運?,將計算分解到多個線程中實現
? I/O密集型應?,為了提?性能,將I/O操作重疊。線程可以同時等待不同的I/O操作。

4 線程的缺點

? 性能損失
? ?個很少被外部事件阻塞的計算密集型線程往往?法與其它線程共享同?個處理器。如果計
算密集型線程的數量?可?的處理器多,那么可能會有較?的性能損失,這?的性能損失指
的是增加了額外的同步和調度開銷,?可?的資源不變。
? 健壯性降低
? 編寫多線程需要更全?更深?的考慮,在?個多線程程序?,因時間分配上的細微偏差或者
因共享了不該共享的變量?造成不良影響的可能性是很?的,換句話說線程之間是缺乏保護
的。
? 缺乏訪問控制
? 進程是訪問控制的基本粒度,在?個線程中調?某些OS函數會對整個進程造成影響。
? 編程難度提?
? 編寫與調試?個多線程程序?單線程程序困難得多

5 線程異常

? 單個線程如果出現除零,野指針問題導致線程崩潰,進程也會隨著崩潰
? 線程是進程的執?分?,線程出異常,就類似進程出異常,進?觸發信號機制,終?進程,進程
終?,該進程內的所有線程也就隨即退出

6 線程?途

? 合理的使?多線程,能提?CPU密集型程序的執?效率
? 合理的使?多線程,能提?IO密集型程序的??體驗(如?活中我們?邊寫代碼?邊下載開發?
具,就是多線程運?的?種表現)

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

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

相關文章

【C++】C++11的包裝器:function與bind簡介

各位大佬好&#xff0c;我是落羽&#xff01;一個堅持不斷學習進步的學生。 如果您覺得我的文章還不錯&#xff0c;歡迎多多互三分享交流&#xff0c;一起學習進步&#xff01; 也歡迎關注我的blog主頁: 落羽的落羽 文章目錄一、function1. 概念2. 用法二、bind1. 概念2. 用法…

MySQL高級特性詳解

MySQL高級特性詳解 一、自關聯查詢 概念 自關聯查詢是指一個表與它自己進行連接的查詢。通常用于處理具有層級關系或遞歸結構的數據。 應用場景 員工與上級關系分類的父子關系地區的層級關系 示例 -- 創建員工表 CREATE TABLE employees (emp_id INT PRIMARY KEY,emp_name VARC…

深度學習——調整學習率

學習率調整方法詳解在深度學習訓練過程中&#xff0c;學習率&#xff08;Learning Rate, LR&#xff09; 是影響模型收斂速度和效果的關鍵超參數。學習率過大可能導致訓練不穩定、震蕩甚至無法收斂&#xff1b;學習率過小又會導致收斂過慢甚至陷入局部最優。因此&#xff0c;如…

Java分頁 Element—UI

前端代碼 <div class"block"><span class"demonstration">頁數較少時的效果</span><el-paginationlayout"prev, pager, next":total"50"></el-pagination> </div>參考Element-UI total:0, form: …

html中列表和表格的使用

列表一般來說只有一列一列的進行使用&#xff0c;是一維的列表分為三種列表形式<!-- 列表標簽ul-li:無序列表&#xff0c;必須用 <ul> 當 “容器”&#xff08;代表 “無序列表”&#xff09;&#xff0c;每個條目用 <li> 包起來&#xff08;代表 “列表項”&am…

大學信息查詢平臺:一個現代化的React教育項目

一 項目簡介大學信息查詢平臺是一個基于React Vite Tailwind CSS構建的現代化Web應用&#xff0c;專門用于查詢中國各大高校的詳細信息。該項目不僅功能實用&#xff0c;更在用戶體驗和界面設計上做到了極致。二 核心功能2.1. 智能大學搜索// 搜索功能核心代碼 const searchU…

代碼隨想錄算法訓練營第六天 - 哈希表2 || 454.四數相加II / 383.贖金信 / 15.三數之和 / 18.四數之和

代碼隨想錄算法訓練營第六天 - 哈希表2 || 454.四數相加II / 383.贖金信 / 15.三數之和 / 18.四數之和454.四數相加II解題思路383.贖金信自己解答&#xff1a;代碼隨想錄講解暴力做法哈希表15.三數之和雙指針優化改進18.四數之和自己的解答系統講解454.四數相加II 文檔講解&…

FPGA實現流水式排序算法

該算法采用雙調排序算法&#xff0c;是一種可流水的遞推算法&#xff0c;且算法的消耗時長可算&#xff0c;具體細節參考視頻&#xff1a; https://www.bilibili.com/video/BV1S3thzWEnh/?spm_id_from333.1387.homepage.video_card.click&vd_source69fb997b62efa60ae1add…

平衡車 -- MPU6050

&#x1f308;個人主頁&#xff1a;羽晨同學 &#x1f4ab;個人格言:“成為自己未來的主人~” 傳感器原理 此外&#xff0c;用陀螺儀獲取x,y,z軸的加速度。 初始化 我們現在對MPU6050進行初始化&#xff0c;MPU6050通過I2C總線與單片機進行通信&#xff0c;通過的是PB8和PB…

在電路浪涌測試中,TVS(瞬態電壓抑制二極管)的防護效果確實會受到陪測設備中去耦網絡(Decoupling Network,DN)的顯著影響

在電路浪涌測試中&#xff0c;TVS&#xff08;瞬態電壓抑制二極管&#xff09;的防護效果確實會受到陪測設備中去耦網絡&#xff08;Decoupling Network&#xff0c;DN&#xff09;的顯著影響&#xff0c;這一現象與浪涌能量的傳遞路徑、阻抗匹配及信號完整性密切相關。結合 AD…

Redis之分布式鎖與緩存設計

1、分布式鎖 1.1、超賣問題/*** 存在庫存超賣的不安全問題*/private void deductStock() {int stockTotal Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));if (stockTotal > 0) { // 這里存在多個線程、進程同時判斷通過&#xff0c;然后超買…

靜態住宅IP的特點

穩定性高&#xff1a;與動態IP地址相比&#xff0c;靜態住宅IP不會不定時變更&#xff0c;能確保業務在網絡環境中的一致性和連貫性&#xff0c;適合需要長期維持同一身份的場景&#xff0c;如跨境電商業務等3。安全性強&#xff1a;由于其住宅屬性&#xff0c;看起來更像是正常…

Linux 編譯 Android 版 QGroundControl 軟件并運行到手機上

Linux 編譯 Android 版 QGroundControl 軟件并運行到手機上環境說明操作步驟一、參考上一篇文章在電腦端把環境搭建好二、配置 Qt Creator 的 Android 環境環境說明 電腦系統 Ubuntu 22.04 qgroundcontrol master 分支 Qt 6.8.3 操作步驟 一、參考上一篇文章在電腦端把環境搭…

Python 2025:量化金融與智能交易的新紀元

當Python遇見金融大數據&#xff0c;算法交易正迎來前所未有的技術變革在2025年的技術浪潮中&#xff0c;Python已經從一個"膠水語言"蛻變為金融科技領域的核心驅動力。根據GitHub 2025年度報告&#xff0c;Python在量化金融項目中的使用率增長了217%&#xff0c;在對…

[論文閱讀] 人工智能 + 軟件工程 | TDD痛點破解:LLM自動生成測試骨架靠譜嗎?靜態分析+專家評審給出答案

TDD痛點破解&#xff1a;LLM自動生成測試骨架靠譜嗎&#xff1f;靜態分析專家評審給出答案 論文信息項目詳情論文原標題Evaluation of Large Language Models for Generating RSpec Test Skeletons in Ruby on Rails論文鏈接https://arxiv.org/pdf/2509.04644一段話總結 該研究…

開源PSS解析器1

本章介紹另一個開源PSS解析工具zuspec&#xff1a; zuspec 提供了一組用于處理 actions relationship level 的工具 &#xff08;ARL&#xff09; 模型&#xff0c;主要是使用 Accellera 便攜式測試和刺激 &#xff08;PSS&#xff09; 語言描述的模型。ARL 模型用于為數字設計…

26考研——內存管理_內存管理策略(3)

408答疑 文章目錄一、內存管理策略1、內存管理的基本原理和要求1.1、相關概念1.2、邏輯地址與物理地址1.3、程序的鏈接與裝入1.4、進程的內存映像1.5、內存保護1.6、內存共享1.7、內存分配與回收1.8、在存儲管理中涉及到兩個問題2、連續分配管理方式2.1、相關概念2.2、單一連續…

Python爬蟲實戰:研究Event Handling機制,構建在線教育平臺的課程數據采集和分析系統

1. 引言 1.1 研究背景與意義 在大數據時代,互聯網作為全球最大的信息載體,蘊含著海量有價值的數據。這些數據涵蓋了商業交易、用戶行為、社會趨勢等多個領域,對企業決策、學術研究和社會管理具有重要參考價值。如何高效、準確地獲取這些數據并進行深度分析,成為當前數據科…

docker 安裝 redis 并設置 volumes 并修改 修改密碼(四)

設置新密碼: 127.0.0.1:6379> CONFIG SET requirepass newpassword OK驗證新密碼: 127.0.0.1:6379> AUTH newpassword OK更新配置文件: 編輯主機的配置文件/data/redis/conf/redis.conf,將requirepass的值修改為新密碼: requirepass newpassword重啟容器以使配置…

NBA球星知識大挑戰:基于 PyQt5 的球星認識小游戲

NBA球星知識大挑戰&#xff1a;基于 PyQt5 的球星認識小游戲 代碼詳見&#xff1a;https://github.com/xiaozhou-alt/NBA_Players_Recognition 文章目錄 NBA球星知識大挑戰&#xff1a;基于 PyQt5 的球星認識小游戲一、項目介紹二、文件夾結構三、項目實現1. 自定義動畫按鈕&a…