【操作系统原理】三级项目-基于并行计算的的单词统计

前言

这是当时选修《操作系统原理》时需要做的一个实验项目,也是三级项目,选题选的是第二章有关并行计算的实验,这个项目有匿名版的PPT和视频,可以私我,发送“基于并行计算的的单词统计”即可获取整个项目的压缩包。
在这里插入图片描述

1.软硬件环境

  • 操作系统:ubuntu22.04.3LTS

  • 硬件要求:3G内存、4个处理器

  • 开发工具:Vscode

  • 第三方库和依赖项:<stdio.h> 、<pthread.h>、<ctype.h> 、<stdlib.h>、 、、

2.实验名称

基于分布并行计算的多线程单词统计工具

2.1实验解决方案

  1. 区分单词原则:
    凡是一个非字母或数字的字符跟在字母或数字的后面,那么这个字母或数字就是单词的结尾。
  2. 总单词数访问互斥原则:
    允许线程使用互斥锁来修改临界资源,确保线程间的同步与协作。如果两个线程需要安全的共享一个公共计数器,需要把公共计数器加锁,线程需要访问称为互斥锁的变量,它可以使线程间很好的合作,避免对于资源的访问冲突。
  3. 基于线程的分布并行计算原则:
    在count_words函数使用了一个线程池来并行处理文件中的数据。这个函数首先将文件分割成多个部分,然后创建一个线程池,每个线程处理文件的一个部分。每个线程都有一个本地的单词计数器,当它完成对其部分的处理后,它会更新全局的单词计数器。

2.2 程序代码

v1.0——word_count_base.cpp
#include <stdio.h>  
#include <pthread.h>  
#include <ctype.h>  
#include <stdlib.h>  
  
pthread_mutex_t counter_lock = PTHREAD_MUTEX_INITIALIZER; // 互斥锁  
int total_words = 0;                                      // 单词总数  
  
// 统计单词数  
void *count_words(void *f)  
{  
    char *filename = (char *)f; // 文件名  
    FILE *fp;                   // 文件指针  
    int c, prevc = '\0';        // c为当前字符,prevc为前一个字符  
  
    if ((fp = fopen(filename, "r")) != NULL)  
    { // 打开文件  
        while ((c = getc(fp)) != EOF)  
        { // 读取文件  
            if (!isalnum(c) && isalnum(prevc))  
            {                                        // 如果当前字符不是字母或数字,前一个字符是字母或数字  
                pthread_mutex_lock(&counter_lock);   // 加锁  
                total_words++;                       // 单词数加1  
                pthread_mutex_unlock(&counter_lock); // 解锁  
            }  
            prevc = c; // 更新前一个字符  
        }  
        fclose(fp); // 关闭文件  
    }  
    else  
    {                     // 打开文件失败  
        perror(filename); // 打印错误信息  
    }  
    return NULL;  
}  
  
int main(int ac, char *av[])  
{  
    pthread_t t1, t2; // 两个线程  
  
    if (ac != 3)  
    {                                            // 参数错误  
        printf("Usage:%s file1 file2\n", av[0]); // 打印使用方法  
        exit(1);  
    }  
  
    pthread_create(&t1, NULL, count_words, av[1]); // 创建线程1  
    pthread_create(&t2, NULL, count_words, av[2]); // 创建线程2  
  
    pthread_join(t1, NULL); // 等待线程1结束  
    pthread_join(t2, NULL); // 等待线程2结束  
  
    printf("Total words: %d\n", total_words); // 打印单词总数  
  
    return 0;  
}  
v1.1——word_count_with_time.cpp
#include <stdio.h> // 引入标准输入输出库  
#include <pthread.h> // 引入线程库  
#include <ctype.h> // 引入isalnum函数  
#include <stdlib.h> // 引入exit函数  
#include <chrono> // 引入时间库  
  
pthread_mutex_t counter_lock = PTHREAD_MUTEX_INITIALIZER; // 互斥锁  
int total_words = 0;                                      // 单词总数  
  
// 统计单词数  
void *count_words(void *f)  
{  
    char *filename = (char *)f; // 文件名  
    FILE *fp;                   // 文件指针  
    int c, prevc = '\0';        // c为当前字符,prevc为前一个字符  
  
    auto start = std::chrono::high_resolution_clock::now(); // 记录开始时间  
  
    if ((fp = fopen(filename, "r")) != NULL)  
    { // 打开文件  
        while ((c = getc(fp)) != EOF)  
        { // 读取文件  
            if (!isalnum(c) && isalnum(prevc))  
            {                                        // 如果当前字符不是字母或数字,前一个字符是字母或数字  
                pthread_mutex_lock(&counter_lock);   // 加锁  
                total_words++;                       // 单词数加1  
                pthread_mutex_unlock(&counter_lock); // 解锁  
            }  
            prevc = c; // 更新前一个字符  
        }  
        fclose(fp); // 关闭文件  
    }  
    else  
    {                     // 打开文件失败  
        perror(filename); // 打印错误信息  
    }  
  
    auto end = std::chrono::high_resolution_clock::now(); // 记录结束时间  
    std::chrono::duration<double> diff = end - start; // 计算时间差  
  
    printf("Thread time taken: %f seconds\n", diff.count()); // 打印所用时间  
      
    return NULL;  
}  
  
int main(int ac, char *av[])  
{  
    pthread_t t1, t2; // 两个线程  
  
    if (ac != 3)  
    {                                            // 参数错误  
        printf("Usage:%s file1 file2\n", av[0]); // 打印使用方法  
        exit(1);  
    }  
  
    auto start = std::chrono::high_resolution_clock::now(); // 记录开始时间  
  
    pthread_create(&t1, NULL, count_words, av[1]); // 创建线程1  
    pthread_create(&t2, NULL, count_words, av[2]); // 创建线程2  
  
    pthread_join(t1, NULL); // 等待线程1结束  
    pthread_join(t2, NULL); // 等待线程2结束  
  
    auto end = std::chrono::high_resolution_clock::now(); // 记录结束时间  
  
    std::chrono::duration<double> diff = end - start; // 计算时间差  
  
    printf("Total words: %d\n", total_words); // 打印单词总数  
    printf("Time taken: %f seconds\n", diff.count()); // 打印所用时间  
  
    return 0;  
}  
v1.2——word_count_thread_arr.cpp
#include <stdio.h>   // 引入标准输入输出库  
#include <pthread.h> // 引入线程库  
#include <ctype.h>   // 引入isalnum函数  
#include <stdlib.h>  // 引入exit函数  
#include <chrono>    // 引入时间库  
  
pthread_mutex_t counter_lock = PTHREAD_MUTEX_INITIALIZER; // 互斥锁  
int total_words = 0;                                      // 单词总数  
  
// 统计单词数  
void *count_words(void *f)  
{  
    char *filename = (char *)f; // 文件名  
    FILE *fp;                   // 文件指针  
    int c, prevc = '\0';        // c为当前字符,prevc为前一个字符  
  
    auto start = std::chrono::high_resolution_clock::now(); // 记录开始时间  
  
    if ((fp = fopen(filename, "r")) != NULL)  
    { // 打开文件  
        while ((c = getc(fp)) != EOF)  
        { // 读取文件  
            if (!isalnum(c) && isalnum(prevc))  
            {                                        // 如果当前字符不是字母或数字,前一个字符是字母或数字  
                pthread_mutex_lock(&counter_lock);   // 加锁  
                total_words++;                       // 单词数加1  
                pthread_mutex_unlock(&counter_lock); // 解锁  
            }  
            prevc = c; // 更新前一个字符  
        }  
        fclose(fp); // 关闭文件  
    }  
    else  
    {                     // 打开文件失败  
        perror(filename); // 打印错误信息  
    }  
  
    auto end = std::chrono::high_resolution_clock::now(); // 记录结束时间  
    std::chrono::duration<double> diff = end - start;     // 计算时间差  
  
    printf("Thread time taken: %f seconds\n", diff.count()); // 打印所用时间  
  
    return NULL;  
}  
  
int main(int ac, char *av[])  
{  
    if (ac < 2)  
    {                                                  // 参数错误  
        printf("Usage:%s file1 [file2 ...]\n", av[0]); // 打印使用方法  
        exit(1);  
    }  
  
    auto start = std::chrono::high_resolution_clock::now(); // 记录开始时间  
  
    int num_files = ac - 1;                        // 文件数量  
    pthread_t *threads = new pthread_t[num_files]; // 创建线程数组  
  
    for (int i = 0; i < num_files; ++i)  
    {  
        pthread_create(&threads[i], NULL, count_words, av[i + 1]); // 创建线程  
    }  
  
    for (int i = 0; i < num_files; ++i)  
    {  
        pthread_join(threads[i], NULL); // 等待线程结束  
    }  
  
    delete[] threads; // 删除线程数组  
  
    auto end = std::chrono::high_resolution_clock::now(); // 记录结束时间  
  
    std::chrono::duration<double> diff = end - start; // 计算时间差  
  
    printf("Total words: %d\n", total_words);         // 打印单词总数  
    printf("Time taken: %f seconds\n", diff.count()); // 打印所用时间  
  
    return 0;  
}  
v1.3——word_count_thread_arr_better.cpp
#include <stdio.h>   // 引入标准输入输出库  
#include <pthread.h> // 引入线程库  
#include <ctype.h>   // 引入isalnum函数  
#include <stdlib.h>  // 引入exit函数  
#include <chrono>    // 引入时间库  
  
pthread_mutex_t counter_lock = PTHREAD_MUTEX_INITIALIZER; // 互斥锁  
int total_words = 0;                                      // 单词总数  
  
// 统计单词数  
void *count_words(void *f)  
{  
    char *filename = (char *)f; // 文件名  
    FILE *fp;                   // 文件指针  
    int c, prevc = '\0';        // c为当前字符,prevc为前一个字符  
    int local_word_count = 0;   // 本地单词数  
  
    auto start = std::chrono::high_resolution_clock::now(); // 记录开始时间  
    std::time_t start_time = std::chrono::system_clock::to_time_t(start);  
    printf("%-30s: Start time: %s", filename, std::ctime(&start_time)); // 打印开始时间  
  
    if ((fp = fopen(filename, "r")) != NULL)  
    { // 打开文件  
        while ((c = getc(fp)) != EOF)  
        { // 读取文件  
            if (!isalnum(c) && isalnum(prevc))  
            {                                        // 如果当前字符不是字母或数字,前一个字符是字母或数字  
                pthread_mutex_lock(&counter_lock);   // 加锁  
                total_words++;                       // 单词数加1  
                pthread_mutex_unlock(&counter_lock); // 解锁  
            }  
            if (!isalnum(c) && isalnum(prevc))  
            {  
                local_word_count++; // 单词数加1  
            }  
            prevc = c; // 更新前一个字符  
        }  
        fclose(fp); // 关闭文件  
    }  
    else  
    {                     // 打开文件失败  
        perror(filename); // 打印错误信息  
    }  
  
    auto end = std::chrono::high_resolution_clock::now(); // 记录结束时间  
  
   auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); // 计算时间差  
  
    int milliseconds = duration.count() % 1000; // 获取毫秒  
    int seconds = (duration.count() / 1000) % 60; // 获取秒  
    int minutes = (duration.count() / 1000) / 60; // 获取分钟  
  
    printf("%-30s: Word count: %-30d Thread time taken: %d minutes %d seconds %d milliseconds\n", filename, local_word_count, minutes, seconds, milliseconds); // 打印文件名、单词数和所用时间  
      
    return NULL;  
}  
  
int main(int ac, char *av[])  
{  
    if (ac < 2)  
    {                                                  // 参数错误  
        printf("Usage:%s file1 [file2 ...]\n", av[0]); // 打印使用方法  
        exit(1);  
    }  
  
    auto start = std::chrono::high_resolution_clock::now(); // 记录开始时间  
  
    int num_files = ac - 1;                        // 文件数量  
    pthread_t *threads = new pthread_t[num_files]; // 创建线程数组  
  
    for (int i = 0; i < num_files; ++i)  
    {  
        pthread_create(&threads[i], NULL, count_words, av[i + 1]); // 创建线程  
    }  
  
    for (int i = 0; i < num_files; ++i)  
    {  
        pthread_join(threads[i], NULL); // 等待线程结束  
    }  
  
    delete[] threads; // 删除线程数组  
  
    auto end = std::chrono::high_resolution_clock::now(); // 记录结束时间  
  
    std::chrono::duration<double> diff = end - start; // 计算时间差  
  
    printf("Total words: %d\n", total_words);         // 打印单词总数  
    printf("Time taken: %f seconds\n", diff.count()); // 打印所用时间  
  
    return 0;  
}  
v1.4——word_count_final.cpp
#include <stdio.h>   // 引入标准输入输出库  
#include <pthread.h> // 引入线程库  
#include <ctype.h>   // 引入isalnum函数  
#include <stdlib.h>  // 引入exit函数  
#include <chrono>    // 引入时间库  
#include <thread>    // 引入线程库  
#include <vector>    // 引入向量库  
  
pthread_mutex_t counter_lock = PTHREAD_MUTEX_INITIALIZER; // 互斥锁  
int total_words = 0;                                      // 单词总数  
  
// 统计单词数  
void *count_words(void *f)  
{  
    char *filename = (char *)f; // 文件名  
    int local_word_count = 0;  // 本地单词数  
    FILE *fp;                   // 文件指针  
  
    auto start = std::chrono::high_resolution_clock::now(); // 记录开始时间  
    std::time_t start_time = std::chrono::system_clock::to_time_t(start);  
    printf("%-30s: Start time: %s", filename, std::ctime(&start_time)); // 打印开始时间  
  
    if ((fp = fopen(filename, "r")) != NULL)  
    { // 打开文件  
        fseek(fp, 0, SEEK_END);  
        long file_size = ftell(fp); // 获取文件大小  
        fseek(fp, 0, SEEK_SET);  
  
        char *file_content = new char[file_size];  
        fread(file_content, 1, file_size, fp); // 读取整个文件到内存中  
        fclose(fp);                            // 关闭文件  
  
        int num_threads = std::thread::hardware_concurrency(); // 获取硬件支持的并发线程数  
        long part_size = file_size / num_threads;              // 计算每个线程需要处理的部分大小  
  
        std::vector<std::thread> threads;                   // 线程池  
        std::vector<int> local_word_counts(num_threads, 0); // 每个线程的单词数  
        for (int i = 0; i < num_threads; ++i)  
        {  
            threads.push_back(std::thread([=, &local_word_counts]()  
                                          {  
        int c, prevc = '\0';        // c为当前字符,prevc为前一个字符  
  
        long start_pos = i * part_size; // 计算这个线程需要处理的部分的开始位置  
        long end_pos = (i == num_threads - 1) ? file_size : (i + 1) * part_size; // 计算这个线程需要处理的部分的结束位置  
        for (long pos = start_pos; pos < end_pos; ++pos)  
        { // 读取文件  
            c = file_content[pos];  
            if (!isalnum(c) && isalnum(prevc))  
            {                                        // 如果当前字符不是字母或数字,前一个字符是字母或数字  
                pthread_mutex_lock(&counter_lock);   // 加锁  
                total_words++;                       // 单词数加1  
                pthread_mutex_unlock(&counter_lock); // 解锁  
                local_word_counts[i]++; // 单词数加1  
            }  
            prevc = c; // 更新前一个字符  
        } }));  
        }  
  
        for (int i = 0; i < num_threads; ++i)  
        {  
            threads[i].join();                        // 等待线程完成  
            local_word_count += local_word_counts[i]; // 累加本地单词数  
        }  
  
        delete[] file_content; // 释放内存  
    }  
    else  
    {                     // 打开文件失败  
        perror(filename); // 打印错误信息  
    }  
  
    auto end = std::chrono::high_resolution_clock::now(); // 记录结束时间  
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);  
    printf("%-30s: End time: %s", filename, std::ctime(&end_time)); // 打印开始时间  
  
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); // 计算时间差  
  
    int milliseconds = duration.count() % 1000;   // 获取毫秒  
    int seconds = (duration.count() / 1000) % 60; // 获取秒  
    int minutes = (duration.count() / 1000) / 60; // 获取分钟  
  
    printf("%-30s: Word count: %-30d Thread time taken: %d minutes %d seconds %d milliseconds\n", filename, local_word_count, minutes, seconds, milliseconds); // 打印文件名、单词数和所用时间  
  
    return NULL;  
}  
  
int main(int ac, char *av[])  
{  
    if (ac < 2)  
    {                                                  // 参数错误  
        printf("Usage:%s file1 [file2 ...]\n", av[0]); // 打印使用方法  
        exit(1);  
    }  
  
    auto start = std::chrono::high_resolution_clock::now(); // 记录开始时间  
  
    int num_files = ac - 1;                        // 文件数量  
    pthread_t *threads = new pthread_t[num_files]; // 创建线程数组  
  
    for (int i = 0; i < num_files; ++i)  
    {  
        pthread_create(&threads[i], NULL, count_words, av[i + 1]); // 创建线程  
    }  
  
    for (int i = 0; i < num_files; ++i)  
    {  
        pthread_join(threads[i], NULL); // 等待线程结束  
    }  
  
    delete[] threads; // 删除线程数组  
  
    auto end = std::chrono::high_resolution_clock::now(); // 记录结束时间  
  
    std::chrono::duration<double> diff = end - start; // 计算时间差  
  
    printf("Total words: %d\n", total_words);         // 打印单词总数  
    printf("Time taken: %f seconds\n", diff.count()); // 打印所用时间  
  
    return 0;  
}  

3.测试(测试用例设计、运行结果)

  1. v1.0——word_count_base.cpp
    在这里插入图片描述

  2. v1.1——word_count_with_time_count.cpp
    在这里插入图片描述

  3. v1.2——word_count_thread_arr.cpp
    在这里插入图片描述

  4. v1.3——word_count_thread_arr_better.cpp
    在这里插入图片描述

  5. v.1.4——word_count_final.cpp
    在这里插入图片描述

5.系统特色以及可扩展点

5.1 特色

这是是一个使用 POSIX 线程(pthread)的程序,它能并发地计算多个文件中的单词数及单次总数。每个文件由一个独立的线程处理,所有线程都能够更新全局变量 total_words 来累计所有文件中的单词总数。其中的互斥锁 counter_lock 用于同步对共享变量 total_words 的访问。

5.2 可扩展点

  • 性能优化:可以使用条件变量或其他同步机制,减少互斥锁的使用,以提高并发性。
  • 动态线程管理:使用线程池来管理线程,而不是为每个文件创建一个线程,这在文件数量特别多时能够提高效率。
  • 支持更多文件格式:目前的程序假设所有文件都是文本文件,并使用 isalnum 函数来检测单词。可以扩展支持其他文件格式,比如PDF或Word文档。
  • Unicode支持:增加对非ASCII字符的支持,识别其他语言的单词。
  • 用户交互:允许用户在程序运行时进行交互,比如取消正在处理的文件或查询当前处理的状态

6.感想

通过上述代码我们展示了基本的线程创建、同步和资源管理。但上述程序仍有很大改进空间,包括优化性能、提高错误处理能力以及增加新功能的可能性等等。

结束语

如果有疑问欢迎大家留言讨论,你如果觉得这篇文章对你有帮助可以给我一个免费的赞吗?你们的认可是我最大的分享动力!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/717292.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java:【@ComponentScan】和【@SpringBootApplication】扫包范围的冲突

# 代码结构如下&#xff1a; 注意【com.chz.myBean.branch】和【com.chz.myBean.main】这两个包是没有生重叠的。 主程序【MyBeanTest1、MyBeanTest2、MyBeanTest3】这两个类是在包【com.chz.myBean.main】下 # 示例代码 【pom.xml】 <dependency><groupId>org.…

基本表的定义:创建表、修改表、删除表

一、创建数据库与打开数据库 学生选课数据库 学生&#xff08;学号&#xff0c;姓名&#xff0c;性别&#xff0c;出生时间&#xff0c;所在系&#xff09; 课程&#xff08;课程编号&#xff0c;课程名&#xff0c;先修课程号&#xff09; 选课&#xff08;学号&#xff0…

【机器学习300问】120、该怎么用RNN来构建语言模型?

一、基本概念补充 在构建语言模型之前补充几个自然语言处理&#xff08;NLP&#xff09;基本概念。 &#xff08;1&#xff09;语料库&#xff08;Corpus&#xff09; ① 语料库的定义 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;语料库是一个经过组织和加工…

二叉树-根据先序遍历和中序遍历序列重建二叉树

目录 一、问题描述 二、解题思路 1.首先明确先序遍历和中序遍历的性质&#xff1a; 2.确定根节点及左右子树 3.对子树进行递归操作 4.递归返回条件 三、代码实现 四、刷题链接 一、问题描述 二、解题思路 1.首先明确先序遍历和中序遍历的性质&#xff1a; 先序遍历&am…

探索比特币多面体

目录 前言 一、比特币挖矿 1.挖矿设备的演化 2.矿池 二、比特币脚本 1.交易结构 2.交易的输入 3.交易的输出 4.P2PK 输入输出脚本的形式 实际执行情况 5.P2PKH 输入输出脚本的形式 实际执行情况 6.P2SH 输入输出脚本的形式 7.进一步说明 8.多重签名 9.脚本执…

Graphviz——安装、绘制可视化协议状态机(Python)

1、简介 Graphviz 是一个开源的图形可视化软件包&#xff0c;特别擅长绘制有向图和无向图等结构化图形。它非常适合用于生成各种图表&#xff0c;例如流程图、网络图、状态机图、层次结构图等。Graphviz 的主要组件 dot: 这是Graphviz最常用的布局程序&#xff0c;用于创建有向…

(杭州中科微)全星座定位导航模块GM32的应用推荐及性能指标解析

1、 关于GNSS的原理&#xff1a; 它是通过接收来自地球轨道上的W星信号&#xff0c;并利用信号传播延迟的原理&#xff0c;计算与接收器之间的距离&#xff0c;从而实现对接收器位置的精确测量。 而GNSS的定位原理&#xff1a;W星导航系统GNSS接收机主要是通过三边测量法&…

Postgresql配置SSL连接

1、系统需要有openssl、openssl-devel包 yum -y install openssl openssl-devel 2、查看当前数据库是否使用openssl编译 pg_config|grep CONFIGURE 如果没有重新编译 make clean make && make install 3、服务器端证书配置 服务器端需生成三个文件: root.crt(根证…

如何用stable diffusion画出这种风景幻视画?

最近出现了一种奇怪的表情包。 看到小图的时候有几个字&#xff0c;点看一看却是一张正常的图片。 比如&#xff0c;看一个有意思的图&#xff0c;这两张图的预览模式下有明显的“银河”两字。 点开放大呢&#xff1f; 竟然是服饰的形状和颜色。 再看一张类似效果的&#xf…

Java_JDK下载与环境变量配置

目录 一、JDK下载安装 二、安装后配置环境变量 三、在编辑器里使用JDK 一、JDK下载安装 JDK 是Java开发工具包&#xff0c;它提供了用于开发和运行Java程序所需的工具和库。JDK包括Java编译器、Java虚拟机、Java标准库等。在IDEA中使用Java语言编写代码时&#xff0c;需要安…

20240617通过串口配置索尼SONY的HDMI OUT输出的8530机芯

20240617通过串口配置索尼SONY的HDMI OUT输出的8530机芯 2024/6/17 15:54 缘起&#xff1a;需要在RK3588开发板OK3588-C上使用SONY的8530机芯。特意熟悉8530的串口命令&#xff01; 目的&#xff1a;需要配置SONY的8530机芯为RGB输出&#xff0c;4K分辨率。 串口波特率&#x…

Redis 管道

Redis的消息交互 当我们使用客户端对Redis进行一次操作时&#xff0c;如下图所示&#xff0c;客户端将请求传送给服务器&#xff0c;服务器处理完毕后&#xff0c;再将响应回复给客户端&#xff0c;这要花费一个网络数据包来回的时间。 如果连续执行多条指令&#xff0c;那就会…

Elixir学习笔记——编写文档

Elixir 将文档视为一等级别类。文档必须易于编写且易于阅读。在本指南中&#xff0c;您将学习如何在 Elixir 中编写文档&#xff0c;涵盖模块属性、样式实践和文档测试等结构。 Markdown Elixir 文档是使用 Markdown 编写的。网上有很多关于 Markdown 的指南&#xff0c;我们…

根据配置的参数规格生成商品SKU

参数规格如下&#xff1a; let specParam [[红色,绿色,白色,黄色], [大,小]]js部分&#xff1a; let getSpecParamCom (specData, index) > {for (let i 0; i < specData[index].length; i) {tempResult[index] specData[index][i];if (index ! specData.length - …

鸿蒙原生App开发之:套用混合app开发思路

2024年&#xff0c;似乎华为迎来了新的企业机遇--鸿蒙独立操作系统。 受到全球国际形势的影响&#xff0c;加之第四次科技革命&#xff08;AI革命&#xff09;冷不丁的出现&#xff0c;在他国AI技术领先的前提下&#xff0c;中国自主研发的独立操作系统再次提上新的战略高度。…

Javaweb08-JDBC数据库连接技术

JDBC数据库连接技术 **原理&#xff1a;**JDBC在应用程序与数据库之间起到了一个桥梁作用&#xff0c;当应用程序使用JDBC访问特定的数据库时&#xff0c;需要通过不同数据库驱动与不同的数据库进行连接&#xff0c;连接后即可对数据库进行相应的操作。 一.Jdbc API 1.Driver…

基于Itô扩散过程的交易策略偏微分方程matlab求解与仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于It扩散过程的交易策略偏微分方程,提出了一种确定It扩散过程。通过根据的第一次通过时间来确定问题在这个过程中&#xff0c;我们推导出交易长度的分布函数和密…

Guava-EventBus 源码解析

EventBus 采用发布订阅者模式的实现方式&#xff0c;它实现了泛化的注册方法以及泛化的方法调用,另外还考虑到了多线程的问题,对多线程使用时做了一些优化&#xff0c;观察者模式都比较熟悉&#xff0c;这里会简单介绍一下&#xff0c;重点介绍的是如何泛化的进行方法的注册以及…

网线不通?瞅瞅这里----关于交叉网线的原理。

最近搞了个项目&#xff0c;UDP对接UDP&#xff0c;死活对接不上。 最后发现是交叉网线的事情&#xff0c;在此记录交叉网线的原理。 先说结论&#xff1a;不同设备用直连&#xff0c;相同设备用交叉网线 细说说 1.原理 网线的原理实际就是TX与RX对接。 正常一个设备同时有…

关于使用命令行打开wps word文件

前言 在学习python-docx时&#xff0c;想在完成运行时使用命令行打开生成的docx文件。 总结 在经过尝试后&#xff0c;得出以下代码&#xff1a; commandrstart "C:\Users\86136\AppData\Local\Kingsoft\WPS Office\12.1.0.16929\office6\wps.exe" "./result…