Linux動態頻率調節系統CPUFreq之二:核心(core)架構與API【轉】

来源:https://www.cnblogs.com/linhaostudy/archive/2020/04/28/12793780.html
-Advertisement-
Play Games

"Linux動態頻率調節系統CPUFreq之二:核心(core)架構與API" 上一節中,我們大致地講解了一下CPUFreq在用戶空間的sysfs介面和它的幾個重要的數據結構,同時也提到,CPUFreq子系統把一些公共的代碼邏輯組織在一起,構成了CPUFreq的核心部分,這些公共邏輯向CPUFreq ...


Linux動態頻率調節系統CPUFreq之二:核心(core)架構與API

上一節中,我們大致地講解了一下CPUFreq在用戶空間的sysfs介面和它的幾個重要的數據結構,同時也提到,CPUFreq子系統把一些公共的代碼邏輯組織在一起,構成了CPUFreq的核心部分,這些公共邏輯向CPUFreq和其它內核模塊提供了必要的API,像cpufreq_governor、cpufreq_driver等模塊通過這些API來完成一個完整的CPUFreq體系。這一節我們就來討論一下核心架構的代碼架構以及如何使用這些公共的API介面。

核心部分的代碼都在:/drivers/cpufreq/cpufreq.c中,本系列文章我使用的內核版本是3.10.0.

1. CPUFreq子系統的初始化

先看看具體的代碼:

static int __init cpufreq_core_init(void)
{
        int cpu;
 
        if (cpufreq_disabled())
                return -ENODEV;
 
        for_each_possible_cpu(cpu) {
                per_cpu(cpufreq_policy_cpu, cpu) = -1;
                init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
        }
 
        cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);
        BUG_ON(!cpufreq_global_kobject);
        register_syscore_ops(&cpufreq_syscore_ops);
 
        return 0;
}
core_initcall(cpufreq_core_init);

可見,在系統的啟動階段,經由initcall機制,cpufreq_core_init被調用,由它來完成核心部分的初始化工作,其中:

cpufreq_policy_cpu 是一個per_cpu變數,在smp的系統下,每個cpu可以有自己獨立的調頻policy,也可以所有的cpu都是用一種policy,這時候就有可能出現其中一個cpu管理著某個policy,而其它cpu因為也使用同一個policy,這些cpu的policy的就交由那個管理cpu代管,這個per_cpu變數就是用來記錄各個cpu的policy實際上是由那個cpu進行管理的。初始化時都被初始化為-1了,代表現在還沒有開始進行policy的管理。

接下來的kobject_create_and_add函數在/sys/devices/system/cpu這個節點下建立了一個cpufreq節點,該節點的下麵以後會用來放置當前governor的一些配置參數。參數cpu_subsys是內核的一個全局變數,是由更早期的初始化時初始化的,代碼在drivers/base/cpu.c中:

struct bus_type cpu_subsys = {
        .name = "cpu",
        .dev_name = "cpu",
};
EXPORT_SYMBOL_GPL(cpu_subsys);
 
 
void __init cpu_dev_init(void)
{
        if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups))
                panic("Failed to register CPU subsystem");
 
        cpu_dev_register_generic();
}

這將會建立一根cpu匯流排,匯流排下掛著系統中所有的cpu,cpu匯流排設備的根目錄就位於:/sys/devices/system/cpu,同時,/sys/bus下也會出現一個cpu的匯流排節點。。cpu匯流排設備的根目錄下會依次出現cpu0,cpu1,...... cpux節點,每個cpu對應其中的一個設備節點。CPUFreq子系統利用這個cpu_subsys來獲取系統中的cpu設備,併在這些cpu設備下麵建立相應的cpufreq對象,這個我們在後面再討論。

這樣看來,cpufreq子系統的初始化其實沒有做什麼重要的事情,只是初始化了幾個per_cpu變數和建立了一個cpufreq文件節點。下圖是初始化過程的序列圖:

image

圖 1.1 核心層初始化

2. 註冊cpufreq_governor

系統中可以同時存在多個governor策略,一個policy通過cpufreq_policy結構中的governor指針和某個governor相關聯。要想一個governor被policy使用,首先要把該governor註冊到cpufreq的核心中,我們可以通過核心層提供的API來完成註冊:

int cpufreq_register_governor(struct cpufreq_governor *governor)
{
        int err;
        ......
 
        governor->initialized = 0;
        err = -EBUSY;
        if (__find_governor(governor->name) == NULL) {
                err = 0;
                list_add(&governor->governor_list, &cpufreq_governor_list);
        }
 
        ......
        return err;
}

核心層定義了一個全局鏈表變數:cpufreq_governor_list,註冊函數首先根據governor的名稱,通過__find_governor()函數查找該governor是否已經被註冊過,如果沒有被註冊過,則把代表該governor的結構體添加到cpufreq_governor_list鏈表中。在上一篇中我們提到,目前的內核版本提供了5種governor供我們使用,我們可以通過內核的配置項來選擇需要編譯的governor,同時需要指定一個預設的governor。在cpufreq.h中,將會根據配置項的選擇,把CPUFREQ_DEFAULT_GOVERNOR巨集指向預設governor結構體變數的地址,在註冊cpufreq_driver的階段需要使用這個巨集來設定系統預設使用的governor。

3. 註冊一個cpufreq_driver驅動

與governor不同,系統中只會存在一個cpufreq_driver驅動,根據上一篇Linux動態頻率調節系統CPUFreq之一:概述的介紹,cpufreq_driver是平臺相關的,負責最終實施頻率的調整動作,而選擇工作頻率的策略是由governor完成的。所以,系統中只需要註冊一個cpufreq_driver即可,它只負責知道如何控制該平臺的時鐘系統,從而設定由governor確定的工作頻率。註冊cpufreq_driver驅動會觸發cpufreq核心的一系列額外的初始化動作,第一節所說的核心初始化工作非常簡單,實際上,更多的初始化動作在註冊cpufreq_driver階段完成。核心提供了一個API:cpufreq_register_driver來完成註冊工作。下麵我們分析一下這個函數的工作過程:

int cpufreq_register_driver(struct cpufreq_driver *driver_data)
{
        ......
 
        if (cpufreq_disabled())
                return -ENODEV;
 
        if (!driver_data || !driver_data->verify || !driver_data->init ||
            ((!driver_data->setpolicy) && (!driver_data->target)))
                return -EINVAL;

該API只有一個參數:一個cpufreq_driver指針,driver_data,該結構事先在驅動的代碼中定義,調用該API時作為參數傳入。函數先判斷系統目前是否禁止了調頻功能,然後檢查cpufreq_driver的幾個回調函數是否被實現,由代碼可以看出,verify和init回調函數必須要實現,而setpolicy和target回調則至少要被實現其中的一個。這幾個回調的作用請參考本系列的第一篇文章。接下來:

 write_lock_irqsave(&cpufreq_driver_lock, flags);
        if (cpufreq_driver) {
                write_unlock_irqrestore(&cpufreq_driver_lock, flags);
                return -EBUSY;
        }
        cpufreq_driver = driver_data;
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);

檢查全局變數cpufreq_driver是否已經被賦值,如果沒有,則傳入的參數被賦值給全局變數cpufreq_driver,從而保證了系統中只會註冊一個cpufreq_driver驅動。然後:

        ret = subsys_interface_register(&cpufreq_interface);
        
        ......
        ...... 
 
        register_hotcpu_notifier(&cpufreq_cpu_notifier);

通過subsys_interface_register給每一個cpu建立一個cpufreq_policy,最後註冊cpu hot plug通知,以便在cpu hot plug的時候,能夠動態地處理各個cpu policy之間的關係(比如遷移負責管理的cpu等等)。這裡要重點討論一下subsys_interface_register的過程,回到第一節的內容,我們知道初始化階段,cpu_subsys被建立,從而每個cpu都會在cpu匯流排設備下建立一個屬於自己的設備:sys/devices/system/cpu/cpux。subsys_interface_register負責在cpu_subsys子系統的子設備下麵註冊公共的介面。我們看看參數cpufreq_interface的定義:

static struct subsys_interface cpufreq_interface = {
        .name           = "cpufreq",
        .subsys         = &cpu_subsys,
        .add_dev        = cpufreq_add_dev,
        .remove_dev     = cpufreq_remove_dev,
};

subsys_interface_register函數的代碼我就不再展開了,它的大致作用就是:遍歷子系統下麵的每一個子設備,然後用這個子設備作為參數,調用cpufrq_interface結構的add_dev回調函數,這裡的回調函數被指向了cpufreq_add_dev,它的具體工作方式我們在下一節中討論。

driver註冊完成後,驅動被保存在全局變數cpufreq_driver中,供核心層使用,同時,每個cpu也會建立自己的policy策略,governor也開始工作,實時地監控著cpu的負載並計算合適的工作頻率,然後通過driver調整真正的工作頻率。下圖是cpufreq_driver註冊過程的序列圖:

image

4. 為每個cpu建立頻率調整策略(policy)

為每個cpu建立頻率調整策略實在註冊cpufreq_driver階段的subsys_interface_registe函數中完成的,上一節已經提到,該函數最終會調用cpufreq_add_dev回調函數,現在展開這個函數分析一下:

因為subsys_interface_registe會枚舉各個cpu設備,不管該cpu處於offline還是online狀態,cpufreq_add_dev都會被調用,所以函數的一開始,判斷如果cpu處於offline狀態,直接返回。

static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{
        ......
 
        if (cpu_is_offline(cpu))
                return 0;

如果是smp系統,本cpu的policy可能和其他cpu共同使用同一個policy,並委托另一個叫做管理cpu的cpu進行管理,下麵的代碼判斷這種情況,如果已經委托別的cpu管理,則直接返回,核心層定義了另一個per_cpu變數:cpufreq_cpu_data,用來保存各個cpu所使用的cpufreq_policy結構的指針,cpufreq_cpu_get函數實際上就是通過這個per_cpu變數,獲取該指針,如果該指針非0,代表該cpu已經建立好了它自身的policy(可能是在他之前的管理cpu建立policy期間一併建立的)。

        policy = cpufreq_cpu_get(cpu);
        if (unlikely(policy)) {
                cpufreq_cpu_put(policy);
                return 0;
        }

因為cpu hot plug期間,cpufreq_add_dev也會被調用,下麵的代碼片段檢測該cpu之前是否被hot-unpluged過,如果是,找到其中一個相關的cpu(這些相關的cpu都委托給同一個托管它cpu進行管理,調用cpufreq_add_policy_cpu函數,該函數只是簡單地建立一個cpufreq鏈接,鏈接到管理cpu的cpufreq節點。

       for_each_online_cpu(sibling) {
                struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
                if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
                        read_unlock_irqrestore(&cpufreq_driver_lock, flags);
                        return cpufreq_add_policy_cpu(cpu, sibling, dev);
                }
        }

當這是系統初始化階段第一次調用cpufreq_add_dev時(subsys_interface_register枚舉到的第一個cpu,通常就是cpu0),cpufreq_cpu_data應該為NULL,所以我們要為這樣的cpu分配一個cpufreq_policy結構,並初始化該policy所管理的cpu,包括online的cpus欄位和online+offline的cpu_related欄位,並把自己設置為這個policy的管理cpu,使用預設governor初始化policy->governor欄位,同時吧自己加入到online的cpus欄位中:

        policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
        if (!policy)
                goto nomem_out;
 
        if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
                goto err_free_policy;
 
        if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
                goto err_free_cpumask;
 
        policy->cpu = cpu;
        policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        cpumask_copy(policy->cpus, cpumask_of(cpu));
 
        /* Initially set CPU itself as the policy_cpu */
        per_cpu(cpufreq_policy_cpu, cpu) = cpu;

接下來初始化一個供kobject系統註銷時使用的同步變數,初始化一個workqueue,某些時候不能馬上執行對該policy的更新操作,可以使用該workqueue來延遲執行。

        init_completion(&policy->kobj_unregister);
        INIT_WORK(&policy->update, handle_update);

接著,調用cpufreq_driver的init回調,進一步初始化該policy:

       ret = cpufreq_driver->init(policy);
        if (ret) {
                pr_debug("initialization failed\n");
                goto err_set_policy_cpu;
        }

在上述驅動的初始化內部,應該完成以下工作:

  • 設定該cpu的最大和最小工作頻率
  • 設定該policy的最大和最小工作頻率
  • 設定該policy可供調節的頻率檔位
  • 設定cpu調節頻率時的延遲時間特性
  • 該policy可以管理的cpu個數(policy->cpus)

繼續:

        /* related cpus should atleast have policy->cpus */
        cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);

註釋已經寫的很清楚了,把online的cpu加到代表online+offline的related欄位中。接著,剔除offline的cpu:

        cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);

然後,發出CPUFREQ_START通知:

        blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
                                     CPUFREQ_START, policy);

如果是hot-plug加入的cpu,找出它上次使用的governor:

#ifdef CONFIG_HOTPLUG_CPU
        gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
        if (gov) {
                policy->governor = gov;
                pr_debug("Restoring governor %s for cpu %d\n",
                       policy->governor->name, cpu);
        }
#endif

最後,建立cpu設備下的sysfs文件節點:cpufreq,它的完整路徑是:/sys/devices/system/cpu/cpux/cpufreq,同時,在他的下麵,相應的sysfs節點也同時被建立,節點的內容請參考本系列的第一篇文章:Linux動態頻率調節系統CPUFreq之一:概述:

       ret = cpufreq_add_dev_interface(cpu, policy, dev);

至此,一個cpu的policy建立完成,它的頻率限制條件、使用的governor策略,sysfs文件節點都已經建立完成。需要註意點是,系統中有多少個cpu,cpufreq_add_dev函數就會被調用多少次,最後,每個cpu都會建立自己的policy,當然,也有可能只有部分cpu建立了真正的policy,而其它cpu則委托這些cpu進行policy的管理,關於這一點,一開始讀代碼的時候可能有點困擾,為了搞清楚他們之間的關係,我們再跟入cpufreq_add_dev_interface函數看看:

static int cpufreq_add_dev_interface(unsigned int cpu,
                                     struct cpufreq_policy *policy,
                                     struct device *dev)
{
        ......
 
        /* prepare interface data */
        ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
                                   &dev->kobj, "cpufreq");
        ......
 
        /* set up files for this cpu device */
        drv_attr = cpufreq_driver->attr;
        while ((drv_attr) && (*drv_attr)) {
                ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
                if (ret)
                        goto err_out_kobj_put;
                drv_attr++;
        }

函數的一開始,建立cpufreq文件節點,然後在它的下麵再建立一系列節點,用戶可以通過這些文件節點控制該policy的一些參數。這不是我們的重點,我們看下麵這一段代碼:

        for_each_cpu(j, policy->cpus) {
                per_cpu(cpufreq_cpu_data, j) = policy;
                per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
        }

前面的代碼已經設定了該policy所管理的online cpu:policy->cpus,通過兩個per_cpu變數,這裡把每個online cpu的policy都設置為了本cpu(管理cpu)的policy,並且把所有online的cpu的管理cpu也指定為了本cpu。接下來,cpufreq_add_dev_symlink被調用,所有policy->cpus指定的cpu會建立一個cpufreq鏈接,指向本cpu(管理cpu)的真實cpufreq節點:

        ret = cpufreq_add_dev_symlink(cpu, policy);

註意,假如這時的cpu是cpu0,也就是說,其它cpu的cpufreq_add_dev還沒有被調用,但是在cpufreq_cpu_data中,與之對應的policy指針已經被賦值為cpu0所對應的policy,這樣,回到cpufreq_add_dev函數的開頭部分,當接下其它被認為使用cpu0托管他們的policy的cpu也會進入cpufreq_add_dev函數,但是,因為cpufreq_cpu_data中對應的policy已經在cpu0的建立階段被賦值,所以這些cpu他們不會走完所有的流程,在函數的開頭的判斷部分,判斷cpufreq_cpu_data中cpu對應的policy已經被賦值,就直接返回了。

接著往下看cpufreq_add_dev_interface的代碼:

        memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
        /* assure that the starting sequence is run in __cpufreq_set_policy */
        policy->governor = NULL;
 
        /* set default policy */
        ret = __cpufreq_set_policy(policy, &new_policy);
        policy->user_policy.policy = policy->policy;
        policy->user_policy.governor = policy->governor;

通過__cpufreq_set_policy函數,最終使得該policy正式生效。到這裡,每個cpu的policy已經建立完畢,並正式開始工作。關於__cpufreq_set_policy的代碼這裡就不展開了,我只給出它的序列圖:
image

5. 其它API

cpufreq的核心層除了提供上面幾節討論的註冊governor,註冊cpufreq_driver等API外,還提供了其他一些輔助的API,以方便其它模塊的使用。

  • int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
  • int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);

以上兩個API用於註冊和註銷cpufreq系統的通知消息,第二個參數可以選擇通知的類型,可以有以下兩種類型:

  • CPUFREQ_TRANSITION_NOTIFIER 收到頻率變更通知

  • CPUFREQ_POLICY_NOTIFIER 收到policy更新通知

  • int cpufreq_driver_target(struct cpufreq_policy *policy,
                                     unsigned int target_freq,
                                     unsigned int relation);

  • int __cpufreq_driver_target(struct cpufreq_policy *policy,
                                       unsigned int target_freq,
                                       unsigned int relation);

以上兩個API用來設置cpu的工作頻率,區別在於cpufreq_driver_target是帶鎖的版本,而__cpufreq_driver_target是不帶鎖的版本,如果確定是在governor的上下文中,使用不帶鎖的版本,否則需要使用帶鎖的版本。

  • void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max);

這個API用來檢查並重新設定policy的最大和最小頻率。

  • int cpufreq_update_policy(unsigned int cpu);

這個API用來觸發cpufreq核心進行policy的更新操作。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 八、函數知識與實踐 (一)shell函數語法 1、函數的表示方式 | 第一種語法 | 第二種語法 | 第三種語法 | | | | | | function 函數名(){ } | function 函數名 {} | 函數名() { } | 2、實例:函數的寫法 3、實例:檢測web網站是否正常 wge ...
  • 七、if結構條件句知識與實踐 (一)if條件句單雙分支語法 (二)if條件句多分支語句 1、語句的結構 2、實例:判斷目錄是否存在 3、實例:判斷伺服器記憶體大小 開發shell腳本判斷記憶體是否充足,如果小於100,提示不足,如果大於100提示充足。 [root@centos6 kvm3 script ...
  • 六、shell腳本的條件測試與比較 (一)條件表達式的常見語法 1、條件表達式6種寫法(if,while) 語法1:test 語法2:[ ] 中括弧兩端必須要有空格 語法3:[[]] 兩端必須要有空格 語法4:((測試表達式)) 兩端必不需要空格 語法5:(命令表達式) 語法6: 實際應用展示 ①[ ...
  • Ansible playbook Vault 加密詳解與使用案例 主機規劃 添加用戶賬號 說明: 1、 運維人員使用的登錄賬號; 2、 所有的業務都放在 /app/ 下「yun用戶的家目錄」,避免業務數據亂放; 3、 該用戶也被 ansible 使用,因為幾乎所有的生產環境都是禁止 root 遠程登 ...
  • Ansible-自動化運維工具 ansible簡介 ansible是新出現的自動化運維工具,基於Python開發,集合了眾多運維工具(puppet、chef、func、fabric)的優點,實現了批量系統配置、批量程式部署、批量運行命令等功能。 ansible是基於模塊工作的,本身沒有批量部署能力, ...
  • 從別人哪裡Clone來的項目 git clone https://github.com/XXX/SimpleUI 進入該文件內 cd SimpleUI 刪除原有的.git信息,建議sudo sudo rm -r .git 初始化.git git init 將本地代碼添加到倉庫 git add .// ...
  • 這篇只是簡單記錄自己在Win10下另安裝Ubuntu系統。 不是教程,因為不會。 推薦一個教程:https://blog.csdn.net/weixin_37029453/article/details/80526732 因為想更好的學習使用Linux,便想到在電腦上另外安裝一個Linux系統(wi ...
  • 在這之前肯定很多人都接觸過Linux管理面板:寶塔,寶塔的確非常方便而且好用,安裝也簡單,複製粘貼幾句命令即可安裝完成,且提供免費版。今天呢,民工哥向大家介紹另一個Linux的伺服器管理面板——AppNode,功能豐富,也提供免費版,且是永久免費! 官方地址:https://www.appnode. ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...