鸿蒙应用框架开发【多线程任务】

news2024/11/14 16:05:40

多线程任务

介绍

本示例通过@ohos.taskpool和@ohos.worker接口,展示了如何启动worker线程和taskpool线程。

效果预览

1

使用说明

  1. 在主界面,可以点击字符串排序拷贝文件按钮进入对应的界面;

  2. 点击字符串排序按钮进入多线程界面:

    worker:

    1. 选择Worker页签,输入待排序的字符串,并以逗号分割。
    2. 点击字符串排序按钮,会将排序前的字符串发送给worker线程,在worker线程实现字符串排序,然后将排序后的字符串发送给主线程,主线程中显示排序后的字符串。
    3. 点击清除按钮,清除字符串。

    taskpool:

    1. 选择TaskPool页签,输入待排序的字符串,并以逗号分割。
    2. 点击立即执行按钮,任务执行完成后将排序后的字符串显示出来。
    3. 点击超时3s执行按钮,任务延迟3s后执行,执行完成后将排序后的字符串显示出来。
    4. 点击函数任务按钮,直接调用执行操作,执行完成后将排序后的字符串显示出来。需要注意的是,通过函数任务创建的task任务不支持取消。
    5. 点击取消任务按钮,会取消最后一个未执行的task任务。需要注意的是,只有当任务数大于最大线程数且任务未开始执行时才可以取消成功。
    6. 点击清除按钮,清除字符串。
  3. 点击拷贝文件按钮进入文件拷贝界面:

    选择需要拷贝的文件,然后点击拷贝文件按钮,文件拷贝成功,触发事件日志显示沙箱下文件个数以及显示部分拷贝成功的文件名。

工程目录

├──entry/src/main/ets                         // 代码区
│  ├──common
│  │  ├──Common.ets                           // 公共工具类
│  │  └──Logger.ets                           // 日志工具类
│  ├──component
│  │  ├──TaskPoolTab.ets                      // taskpool页签
│  │  └──WorkerTab.ets                        // worker页签
│  ├──entryability
│  │  └──EntryAbility.ets  
│  ├──model
│  │  ├──MyWorker.ets                         // 批量拷贝文件方法类
│  │  ├──TaskPoolTab.ts                       // taskpool页签
│  │  └──WorkerTab.ts                         // worker页签
│  └──pages
│     ├──CopyFile.ets                         // 拷贝文件页面
│     ├──TaskPoolTab.ets                      // taskpool页签
│     └──WorkerTab.ets                        // worker页签
└──entry/src/main/resources                   // 应用资源目录

具体实现

  • worker页签的实现在字符串排序页面调用,源码参考[StrSort.ets]
/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { WorkerTab } from '../component/WorkerTab';
import { TaskPoolTab } from '../component/TaskPoolTab';

@Entry
@Component
struct Index {
  private controller: TabsController = new TabsController();
  @State index: number = 0;

  @Builder
  tabJsWorker() {
    Column() {
      Text("Worker")
        .width("57vp")
        .height("22vp")
        .position({ x: "0vp", y: "17vp" })
        .fontFamily("HarmonyHeiTi-Medium")
        .fontSize(16)
        .fontColor(this.index === 0 ? "#007DFF" : "#182431")
        .textAlign(TextAlign.Center)
        .lineHeight(22)
        .fontWeight(this.index === 0 ? 500 : 400)
        .opacity(this.index === 0 ? 1 : 0.6)
      Line()
        .width("57vp")
        .height("2vp")
        .position({ x: "0", y: "46vp" })
        .backgroundColor(this.index === 0 ? "#007DFF" : "linear-gradient(269deg,rgba(0,0,0,0.00)%,#FFFFFF 10%)")
    }
    .id("tabJsWorker")
    .width("100%")
    .height("100%")
    .position({ x: "65%", y: "0vp" })
    .onClick(() => {
      this.index = 0;
      this.controller.changeIndex(this.index);
    })
  }

  @Builder
  tabTaskPool() {
    Column() {
      Text("TaskPool")
        .width("68vp")
        .height("22vp")
        .position({ x: "10vp", y: "17vp" })
        .fontFamily("HarmonyHeiTi-Medium")
        .fontSize(16)
        .fontColor(this.index === 1 ? "#007DFF" : "#182431")
        .textAlign(TextAlign.Center)
        .lineHeight(22)
        .fontWeight(this.index === 1 ? 500 : 400)
        .opacity(this.index === 1 ? 1 : 0.6)
      Line()
        .width("68vp")
        .height("2vp")
        .position({ x: "10vp", y: "46vp" })
        .backgroundColor(this.index === 1 ? "#007DFF" : "linear-gradient(269deg,rgba(0,0,0,0.00)%,#FFFFFF 10%)")
    }
    .id("tabTaskPool")
    .height("100%")
    .width("100%")
    .position({ x: "4%", y: "0" })
    .onClick(() => {
      this.index = 1;
      this.controller.changeIndex(this.index);
    })
  }

  build() {
    Row() {
      Column() {
        Text("ConcurrentModule")
          .width("100%")
          .height("41vp")
          .position({ x: "7%", y: "31vp" })
          .fontColor("#182431")
          .fontSize("30fp")
          .fontFamily("HarmonyHeiTi-Bold")
          .lineHeight(41)
          .fontWeight(700)
          .textAlign(TextAlign.Start)

        Tabs({
          barPosition: BarPosition.Start,
          controller: this.controller
        }) {
          TabContent() {
            WorkerTab();
          }
          .width("100%")
          .height("100%")
          .tabBar(this.tabJsWorker)

          TabContent() {
            TaskPoolTab();
          }
          .width("100%")
          .height("100%")
          .tabBar(this.tabTaskPool)
        }
        .width("100%")
        .height("696vp")
        .barWidth("100%")
        .barHeight("56vp")
        .position({ x: "0vp", y: "80vp" })
        .padding({ bottom: "24vp" })
        .backgroundImage("linear-gradient(269deg,rgba(0,0,0,0.00)%,#FFFFFF 10%)")
        .barMode(BarMode.Fixed)
        .onChange((index: number) => {
          this.index = index;
        })
      }
      .backgroundColor("#f1f3f5")
      .width("100%")
      .height("100%")
    }
    .width("100%")
    .height("100%")
  }
}

  • 字符串排序:通过调用executeWorkerFunc()创建一个worker线程,把待排序字符串发送给worker线程,等worker线程排序完成后再把结果返回。

  • 清除:把字符串输入框和结果都清除。

  • taskpool页签的实现在字符串排序页面调用,源码参考[StrSort.ets]

/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { WorkerTab } from '../component/WorkerTab';
import { TaskPoolTab } from '../component/TaskPoolTab';

@Entry
@Component
struct Index {
  private controller: TabsController = new TabsController();
  @State index: number = 0;

  @Builder
  tabJsWorker() {
    Column() {
      Text("Worker")
        .width("57vp")
        .height("22vp")
        .position({ x: "0vp", y: "17vp" })
        .fontFamily("HarmonyHeiTi-Medium")
        .fontSize(16)
        .fontColor(this.index === 0 ? "#007DFF" : "#182431")
        .textAlign(TextAlign.Center)
        .lineHeight(22)
        .fontWeight(this.index === 0 ? 500 : 400)
        .opacity(this.index === 0 ? 1 : 0.6)
      Line()
        .width("57vp")
        .height("2vp")
        .position({ x: "0", y: "46vp" })
        .backgroundColor(this.index === 0 ? "#007DFF" : "linear-gradient(269deg,rgba(0,0,0,0.00)%,#FFFFFF 10%)")
    }
    .id("tabJsWorker")
    .width("100%")
    .height("100%")
    .position({ x: "65%", y: "0vp" })
    .onClick(() => {
      this.index = 0;
      this.controller.changeIndex(this.index);
    })
  }

  @Builder
  tabTaskPool() {
    Column() {
      Text("TaskPool")
        .width("68vp")
        .height("22vp")
        .position({ x: "10vp", y: "17vp" })
        .fontFamily("HarmonyHeiTi-Medium")
        .fontSize(16)
        .fontColor(this.index === 1 ? "#007DFF" : "#182431")
        .textAlign(TextAlign.Center)
        .lineHeight(22)
        .fontWeight(this.index === 1 ? 500 : 400)
        .opacity(this.index === 1 ? 1 : 0.6)
      Line()
        .width("68vp")
        .height("2vp")
        .position({ x: "10vp", y: "46vp" })
        .backgroundColor(this.index === 1 ? "#007DFF" : "linear-gradient(269deg,rgba(0,0,0,0.00)%,#FFFFFF 10%)")
    }
    .id("tabTaskPool")
    .height("100%")
    .width("100%")
    .position({ x: "4%", y: "0" })
    .onClick(() => {
      this.index = 1;
      this.controller.changeIndex(this.index);
    })
  }

  build() {
    Row() {
      Column() {
        Text("ConcurrentModule")
          .width("100%")
          .height("41vp")
          .position({ x: "7%", y: "31vp" })
          .fontColor("#182431")
          .fontSize("30fp")
          .fontFamily("HarmonyHeiTi-Bold")
          .lineHeight(41)
          .fontWeight(700)
          .textAlign(TextAlign.Start)

        Tabs({
          barPosition: BarPosition.Start,
          controller: this.controller
        }) {
          TabContent() {
            WorkerTab();
          }
          .width("100%")
          .height("100%")
          .tabBar(this.tabJsWorker)

          TabContent() {
            TaskPoolTab();
          }
          .width("100%")
          .height("100%")
          .tabBar(this.tabTaskPool)
        }
        .width("100%")
        .height("696vp")
        .barWidth("100%")
        .barHeight("56vp")
        .position({ x: "0vp", y: "80vp" })
        .padding({ bottom: "24vp" })
        .backgroundImage("linear-gradient(269deg,rgba(0,0,0,0.00)%,#FFFFFF 10%)")
        .barMode(BarMode.Fixed)
        .onChange((index: number) => {
          this.index = index;
        })
      }
      .backgroundColor("#f1f3f5")
      .width("100%")
      .height("100%")
    }
    .width("100%")
    .height("100%")
  }
}

  • 立即执行:通过调用executeImmediately()创建一个task任务,这个任务是立即执行字符串排序。

  • 超时3s执行:通过调用executeDelay()创建一个task任务,这个任务是延迟3s后执行字符串排序。

  • 函数任务:调用executeFunc()接口,不创建task任务,直接调用taskpool.execute()执行字符串排序。

  • 取消任务:调用cancelTask()接口,取消最后一个未执行的task任务。

  • 清除:把字符串输入框和结果都清除。

  • 批量拷贝文件的功能封装在MyWorker,源码参考:[MyWorker.ets]

/*
 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { worker } from '@kit.ArkTS';
import { fileIo } from '@kit.CoreFileKit';
import { Logger, sleep } from '../common/Common';

const CONTENT = 'hello world';
const TAG: string = '[ConcurrentModule].[MyWorker]';
const FILE_NUM: number = 200;
const FILE_NUMBER: number = 9;
const LIST_FILE_TWO: number = 2;
const SLEEP_TIME: number = 100;

let workerInstance: worker.ThreadWorker | null = null;
let fileFlag: boolean = false;

export default class MyFile {
  public baseDir: string = '';
  public filesCount: number = 0;
  private flag: boolean = false;
  public realFileNames: Array<string> = [];

  constructor() {
    this.baseDir = AppStorage.get('sanBoxFileDir') as string;
  }

  readyFileToFileFs(): void {
    let fileFsDir = this.baseDir + '/fileFs';
    try {
      if (!fileIo.accessSync(fileFsDir)) {
        fileIo.mkdirSync(fileFsDir);
      }
      Logger.info(TAG, 'readyFileToFileFs successful');
    } catch (e) {
      Logger.error(TAG, `readyFileToFileFs has failed for: {message: ${(e as Error).message}, ${e}}`);
    }
  }

  // worker file
  readyFilesToWorker(): void {
    let content = CONTENT + CONTENT + new Date() + '\n';
    let workerDir = this.baseDir + '/workerDir';

    try {
      if (!fileIo.accessSync(workerDir)) {
        fileIo.mkdirSync(workerDir);
      }
      Logger.info(TAG, 'readyFilesToWorker dpath = ' + workerDir);
      for (let i = 0; i < FILE_NUM; i++) {
        let myFile = '';
        if (i < FILE_NUMBER) {
          myFile = workerDir + `/TestFile0${i + 1}.txt`;
        } else {
          myFile = workerDir + `/TestFile${i + 1}.txt`;
        }
        Logger.info(TAG, 'readyFilesToWorker myFile = ' + myFile);
        let file = fileIo.openSync(myFile, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE);
        fileIo.writeSync(file.fd, content);
        fileIo.closeSync(file);
      }
      Logger.info(TAG, 'readyFilesToWorker successful');
    } catch (e) {
      Logger.error(TAG, `readyFilesToWorker has failed for: {message: ${(e as Error).message}, ${e}}`);
    }
  }

  async workToCopyFiles(files: Array<string>, filePath: string): Promise<void> {
    try {
      Logger.info(TAG, 'WorkCreator start to create worker');
      let destPath = filePath;
      Logger.info(TAG, 'Workerets destPath ' + destPath);
      if (!fileIo.accessSync(destPath)) {
        fileIo.mkdirSync(destPath);
      }
      if (fileIo.accessSync(destPath)) {
        fileIo.listFile(destPath).then((filenames) => {
          Logger.info(TAG, 'listFile succeed');
          for (let i = 0; i < filenames.length; i++) {
            Logger.info(TAG, 'Workerets fileName: ' + filenames[i]);
          }
        }).catch((err: Error) => {
          Logger.info(TAG, 'list file failed with error message: ' + err.message + ', error: ' + err);
        });
      }
      if (files !== null) {
        this.realFileNames.length = 0;
        for (let i = 0; i < files.length; i++) {
          if (files[i] === 'deletedTag') {
            continue;
          }
          this.realFileNames.push(files[i]);
        }
      }
      let count = this.realFileNames.length;
      for (let j = 0; j < count; j++) {
        Logger.info(TAG, 'workToCopyFiles this.realFileNames = ' + this.realFileNames[j]);
      }
      workerInstance = new worker.ThreadWorker('entry/ets/model/WorkerCopy.ts');
      if (this.realFileNames !== null) {
        let srcPath = this.baseDir + '/workerDir';
        workerInstance.postMessage({
          srcDir: srcPath,
          destDir: destPath,
          fileNames: this.realFileNames
        });
      }

      workerInstance.onexit = (code): void => {
        Logger.info(TAG, `workerInstance::onexit has been exit ${code}`);
      };
      workerInstance.onerror = (err): void => {
        Logger.info(TAG, `workerInstance::onerror has errors: ${JSON.stringify(err)}`);
      };
      workerInstance.onmessageerror = (event): void => {
        Logger.info(TAG, `workerInstance::onmessageerror has errors: ${JSON.stringify(event)}`);
      };
      workerInstance.onmessage = (message): void => {
        Logger.info(TAG, `workerInstance::onmessage receive data: ${JSON.stringify(message.data)}`);
        if (message.data.hasOwnProperty('count')) {
          Logger.info(TAG, `workerInstance::onmessage receive data length = ${message.data.count}`);
          this.filesCount = message.data.count;
          fileFlag = message.data.strFlag;
          this.flag = true;
          let fileName1: string = '';
          let fileName2: string = '';
          for (let i = 0; i < message.data.listFileNames.length; i++) {
            Logger.info(TAG, `Worker workerInstance::onmessage receive listFileNames: ${message.data.listFileNames[i]}`);
          }
          if (message.data.listFileNames[0] !== undefined && message.data.listFileNames[1] !== undefined && message.data.listFileNames[LIST_FILE_TWO] === undefined) {
            fileName1 = message.data.listFileNames[0] + '、';
            fileName2 = message.data.listFileNames[1];
          } else if (message.data.listFileNames[0] !== undefined && message.data.listFileNames[1] === undefined) {
            fileName1 = message.data.listFileNames[0];
            fileName2 = '';
          } else {
            fileName1 = message.data.listFileNames[0] + '、';
            let copyFileLog: string = AppStorage.get('copyFileLog5') as string;
            fileName2 = message.data.listFileNames[1] + copyFileLog;
          }
          AppStorage.setOrCreate('fileListName1', fileName1);
          AppStorage.setOrCreate('fileListName2', fileName2);
          let copyFileLog3: string = AppStorage.get('copyFileLog3') as string;
          let copyFileLog4: string = AppStorage.get('copyFileLog4') as string;
          let copyFileLog = '2、' + fileName1 + fileName2 + copyFileLog3 + 'copy' + copyFileLog4;
          if (fileName1 !== 'undefined、') {
            AppStorage.setOrCreate('copyFileShowLog', copyFileLog);
          } else {
            AppStorage.setOrCreate('copyFileShowLog', $r('app.string.workerLogChooseFile'));
          }
          Logger.info(TAG, `Worker workerInstance::onmessage receive count: ${JSON.stringify(this.filesCount)}`);
        }
        if (this.filesCount !== 0) {
          AppStorage.setOrCreate('fileNumber', JSON.stringify(this.filesCount));
        } else {
          AppStorage.setOrCreate('fileNumber', '0');
          AppStorage.setOrCreate('fileListName1', '');
          AppStorage.setOrCreate('fileListName2', '');
        }
        Logger.info(TAG, 'workerInstance::onmessage Finish to process data from WorkerCopy.ts');
        if (workerInstance !== null) {
          workerInstance.terminate();
        }
      };
      while (!fileFlag) {
        await sleep(SLEEP_TIME);
      }
    } catch (e) {
      Logger.error(TAG, `Worker WorkCreator error package: message: ${(e as Error).message}, ${e}`);
    }
  }

  deleteCopyFile(filePath: string): void {
    Logger.info(TAG, 'deleteCopyFile destCopyFilePath = ' + filePath);
    try {
      if (fileIo.accessSync(filePath)) {
        let isDirectory = fileIo.statSync(filePath).isDirectory();
        if (isDirectory) {
          fileIo.rmdirSync(filePath);
          fileIo.mkdirSync(filePath);
        }
      }
    } catch (e) {
      Logger.error(TAG, `delete workerCopyFile error package: message: ${(e as Error).message}, ${e}`);
    }
  }
}
  • 拷贝文件:在[CopyFile.ets]中调用MyWorker.WorkToCopyFiles(),在WorkToCopyFiles方法中向worker03线程发消息,并在worker03线程中批量拷贝,拷贝完成后将结果返回。

以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:
1

除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下

内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!

鸿蒙【北向应用开发+南向系统层开发】文档

鸿蒙【基础+实战项目】视频

鸿蒙面经

在这里插入图片描述

为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库连接断开后,DBAPI的数据源如何自动重连

现象 在使用DBAPI的过程中&#xff0c;如果网络抖动导致数据库连接不上&#xff0c;发现DBAPI的数据源不能重连&#xff0c;必须重启DBAPI才能连上数据库 解决办法 在数据源的连接池参数配置druid.breakAfterAcquireFailurefalse注意在企业版的4.1.1及以上版本才可以配置连接…

7. LangChain4j如何使用统一api调用?

前言 当我们对接LangChain4j的时候&#xff0c;面对复杂的各种各样的大模型的api的对接&#xff0c;让很多开发者感到力不从心。在每个大模型的api都不一样的时候&#xff1f;该如何快捷的切换模型的使用呢&#xff1f; 这时&#xff0c;One-API应运而生&#xff0c;它以其简洁…

Linux中如何用ida调试fork后的子进程

原文链接 > https://redqx.github.io/linux/2024/07/24/linux-debugfork.html 本文的一些图片引用可能有一些问题, 比如数据不对劲,但无伤大雅 自己懒得粘贴图片了 环境: wsl-kali-2024 ida-7.7 插件: Lazy_ida, 还有一个什么插件不知道什么名字, 可以把汇编转字节码 …

聚焦智慧出行,TDengine 与路特斯科技再度携手

在全球汽车行业向电动化和智能化转型的过程中&#xff0c;智能驾驶技术正迅速成为行业的焦点。随着消费者对出行效率、安全性和便利性的需求不断提升&#xff0c;汽车制造商们需要在全球范围内实现低延迟、高质量的数据传输和处理&#xff0c;以提升用户体验。在此背景下&#…

java学习--练习题

在类中this.属赋值&#xff0c;则外部创建对象调用其值也会随之一样 package com.test01;/* author:我与java相爱相杀---c语言梦开始的地方 今天又是努力学习的一天&#xff01;&#xff01;&#xff01;&#xff01; */ /*1. 在Frock类中声明私有的静态属性currentNum[int类型…

谷粒商城-性能压测

1.压力测试 在项目上线前对其进行压力测试(以每个微服务为单元) 目的:找到系统能承载的最大负荷,找到其他测试方法更难发现的错误(两种类型:内存泄漏,并发与同步). 1.性能指标 响应时间(Response Time (RT)): 响应时间 指用户从客户端发起一个请求开始,到客户端接收到从服务…

学习笔记-系统框图传递函数公式推导

目录 *待了解 现代控制理论和自动控制理论区别 自动控制系统的组成 信号流图 1、系统框图 1.1、信号线、分支点、相加点 1.2、系统各环节间的连接 1.3、 相加点和分支点的等效移动&#xff08;比较点、引出点&#xff09; 2、反馈连接公式推导 2.1、前向通路传递函数…

SpringCloud注册中心(Nacos,Ribbon)

微服务是由多个模块共同组成的&#xff0c;注册中心可以帮助我们沟通这些模块&#xff0c;帮助我们完成模块间的 常见的注册中心 Zookeeper zookeeper它是⼀个分布式服务框架&#xff0c;是Apache Hadoop 的⼀个⼦项⽬&#xff0c;它主要是⽤来解决分布式应 ⽤中经常遇到的⼀…

项目的小结

1.实现实时聊天 1.服务端建立一个ConcurrentHashMap<> 用来存储在线用户&#xff0c;用户账号和socket然后&#xff0c;如果有个人发了信息&#xff0c;就去数据库中查询&#xff0c;然后根据这个在线用户进行传递信息 服务端框架&#xff1a; public class ServerMain {…

转置卷积 transposed convolution

1. 转置卷积 转置卷积&#xff08;Transposed Convolution&#xff09;也叫Fractionally-strided Convolution和Deconvolution&#xff0c;但用的最多的是Transposed Convolution。 注意&#xff1a; 转置卷积不是卷积的逆运算&#xff0c;只会大小恢复为原本大小。转置卷积…

网络安全领域五大注入攻击类型介绍

在网络安全领域&#xff0c;注入攻击是一种常见的攻击方式&#xff0c;攻击者通过向应用程序发送恶意数据来操控应用程序的行为。以下跟随博主通过具体样例一起来掌握以下五种知名的注入攻击类型。 1. SQL注入&#xff08;SQL Injection&#xff09; 1.1. 概述 SQL注入是最常见…

pdf自动生成书签

PDF 自动生成书签&#xff0c;使用软件【PDF补丁丁】 软件官网&#xff1a; https://www.cnblogs.com/pdfpatcher/Github&#xff1a;https://github.com/wmjordan/PDFPatcher参考视频内容&#xff1a;使用PDFPatcher自动生成PDF书签 直接从软件官网下载压缩包&#xff0c;运…

Qt遇到qt自身组件找不到

比如在使用qtcharts的时候&#xff0c;找不到 解决方法&#xff1a; 在cmakelist中添加 find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Charts REQUIRED) 是一个 CMake 命令&#xff0c;用于查找并配置 Qt 库中的特定组件。这条命令的作用是找到 Qt 的主要版本&#xff08;…

高性能 Java 本地缓存 Caffeine 框架介绍及在 SpringBoot 中的使用

在现代应用程序中&#xff0c;缓存是一种重要的性能优化技术&#xff0c;它可以显著减少数据访问延迟&#xff0c;降低服务器负载&#xff0c;提高系统的响应速度。特别是在高并发的场景下&#xff0c;合理地使用缓存能够有效提升系统的稳定性和效率。 Caffeine 是一个高性能的…

Java基础巩固——JDK 8、9新增接口的特性(接口中定义非抽象方法、静态方法和私有方法)

#Java学了这么久&#xff0c;项目也做了&#xff1f;基础知识还不巩固&#xff1f;快来关注我的这篇系列博客——Java基础复习巩固吧# 目录 引言 一、JDK8新特性&#xff1a;允许在接口中定义非抽象方法和静态方法。 注意事项 二、JDK9新特性&#xff1a;允许在接口中定义p…

【推研小灶】复旦与南大之间:一次独特的计算机保研之旅

写在前面 上午10点填完志愿等待复试通知&#xff0c;利用这段时间记录一下我简短的夏令营和预推免。今年变为线下之后&#xff0c;部分学校的入营情况、考核方式有明显变化。加上CS方向保研名额总体变多&#xff0c;形势有点小乱&#xff0c;甚至填报系统都在9.29中秋节当天&a…

AMQP-核心概念-3

本文参考以下链接摘录翻译&#xff1a; https://www.rabbitmq.com/tutorials/amqp-concepts 队列&#xff08;Queues&#xff09; AMQP 0-9-1模型中的队列和其他消息任务队列系统中的队列非常相似&#xff1a;它们用于存储被应用消费的消息。队列和交换机有一些相同的属性&…

2024.7.28周报

目录 摘要 ABSTRACT 一、文献阅读 一、题目 二、摘要 三、创新点 四、文献解读 一、Introduction 二、Saint-Venant方程 三、应用于水道建模的PINN 四、真实场景 五、结论 摘要 本周阅读了一篇题目为Physics-Informed Neural Networks for Modeling Water Flows …

免费【2024】springboot 毕业生学历证明系统

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

vite5+vue3开发阅读APP实战笔记20240725

目前界面长成这样&#xff1a; 配置别名 修改vite.config.js import {defineConfig} from vite import vue from vitejs/plugin-vue import path from "path"// https://vitejs.dev/config/ export default defineConfig({server: {open: true,port: 8088,},plug…