日常应用开发遇到的小问题二三则

news2024/11/30 7:08:51

文章目录

  • 前言
  • Redis问题
    • 启用碎片自动回收失败
    • 启动Redis未脱离终端
  • Vercel问题
    • 未在Vecel团队的人提交无法触发自动部署
    • 更新package.json后部署Vercel时报错
  • Android问题
    • 主动请求通知权限
    • 网络状态变化的监听不能使用静态注册
    • 各种Service介绍和对比
  • 总结

前言

这两天的工作又相对杂乱一些,处理一下A事情,又要搞一搞B事情,需要盯着C事情,还要尝试一下D事情,所以这篇总结没有什么主线,主要目的是记录一下最近解决的问题,先不展开讨论,当类似的问题积累一些再展开描述,我就先记录一下流水账了。

Redis问题

本来是一个常规清理数据,Redis回收内存碎片的操作,但是因redis-server版本问题被迫切换解决方案

启用碎片自动回收失败

127.0.0.1:6379> config set activedefrag yes
(error) ERR Active defragmentation cannot be enabled: it requires a Redis server compiled with 
a modified Jemalloc like the one shipped by default with the Redis source distribution

开启主动碎片整理机制失败,提示错误大概意思是说,当前的 Redis 服务器未使用支持**主动碎片整理(Active Defragmentation)**的 Jemalloc 分配器,因为Redis 的主动碎片整理功能依赖于 Jemalloc 分配器,如果 Redis 是使用其他分配器(如 libc malloc)编译的,或者当前的 Jemalloc 缺乏必要的功能,就会导致该功能无法启用。

可以通过Redis命令 redis-cli INFO memory | grep allocator 来查询,如果显示 mem_allocator:jemalloc,则表示启用了 Jemalloc。如果显示 mem_allocator:libc,则说明当前未使用 Jemalloc,需要重新安装或编译 Redis。

我运行一看当然是 mem_allocator:libc 了,看来没办法进行碎片整理了,幸好是个slave节点,所以我干脆保存数据后重启一下吧。

启动Redis未脱离终端

首先关闭redis服务

shutdown SAVE

这个过程会进行同步存储,所以会给你一种卡死了的状态,因为我这里有90G数据,存储大概用了10多分钟,Redis服务成功关闭

然后按配置文件启动Redis

/usr/local/bin/redis-server ./redis.conf

启动完终端就停在这个了,难道我起了个前台程序?我记得之前都是这么启动的啊,总不能为了脱离终端我还要使用 nohup& 来配合吧,有点low啊,主要是日志是不是就放到nohup.out文件里了,找找有没有配置吧,打开redis.conf文件发现daemonize no,我的天啊,这个redis-server为什么这么与众不同,守护进程模式居然是关着的,虽然说把配置文件改成 daemonize yes 再启动就好了,但是我好奇的是之前是怎么启动的。

我决定不修改配置文件了,保持原来的样子,直接在启动时指定 --daemonize yes 好了,这样可以达到目的,在Linux系统中使用Redis时,命令行参数和配置文件参数(也称为Redis配置)具有不同的优先级。如果同一个配置选项在配置文件和命令行参数中被设置,那么命令行参数将覆盖配置文件中的设置。

Vercel问题

之前简单聊过将Nextjs框架编写的网站部署到Vecel有天然的适应性,因为Vercel背后的团队就是开发出Nextjs框架的那群人,部署到Vercel以后绑定一个域名就可以使用了,不需要自己安装运行环境,不需要配置DN缓存,不需要配置SSL证书,真是方便极了,但免费的账户是有资源限制的,特别是要团队开发的话需要购买付费版本。

未在Vecel团队的人提交无法触发自动部署

用过Vercel就会发现,当通过github导入项目之后,以后每次推送到github后都能自动触发Vercel的网站发布功能,但是未添加到Vercel团队的账号提交时无法触发自动部署,提示

Vercel - No GitHub account was found matching the commit author email address

一种办法就是把所有可能提交的账号都添加到Vercel团队,但是这是要花钱的,每添加一个成员每月$20,还有就是找已经在团队的成员再提交一次,触发自动部署就行了,这个成本也很低,也就是仓库记录不那么干净了而已

git commit --allow-empty -m"trigger redeployment"

更新package.json后部署Vercel时报错

因为我使用 npm install 初始化完项目后,启动时有两个警告

Module not found: Can't resolve 'bufferutil' in 'E:\WorkSpace\nodeweb\qxweb\node_modules\ws\lib'

Import trace for requested module:
./node_modules/ws/lib/buffer-util.js
./node_modules/ws/lib/websocket.js
./node_modules/ws/index.js
./node_modules/@supabase/realtime-js/dist/main/RealtimeClient.js
./node_modules/@supabase/realtime-js/dist/main/index.js
./node_modules/@supabase/supabase-js/dist/main/index.js
./store/SupabaseStore.tsx

./node_modules/ws/lib/validation.js
Module not found: Can't resolve 'utf-8-validate' in 'E:\WorkSpace\nodeweb\qxweb\node_modules\ws\lib'

Import trace for requested module:
./node_modules/ws/lib/validation.js
./node_modules/ws/lib/websocket.js
./node_modules/ws/index.js
./node_modules/@supabase/realtime-js/dist/main/RealtimeClient.js
./node_modules/@supabase/realtime-js/dist/main/index.js
./node_modules/@supabase/supabase-js/dist/main/index.js
./store/SupabaseStore.tsx

所以我就手动安装了这两个库 npm isntall bufferutil utf-8-validate,这就导致我的 package.json 文件更新内容里增加了这两个库的引用版本,提交代码部署Vercel时报错

Running build in Washington, D.C., USA (East) – iad1
Cloning github.com/2338-AI/quantum-solutions-web (Branch: main, Commit: 96249d1)
Previous build cache not available
Cloning completed: 2.607s
Running "vercel build"
Vercel CLI 39.1.1
Detected `pnpm-lock.yaml` version 9 generated by pnpm@9.x
Installing dependencies...
 ERR_PNPM_OUTDATED_LOCKFILE  Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up to date with <ROOT>/package.json
Note that in CI environments this setting is true by default. If you still need to run install in such cases, use "pnpm install --no-frozen-lockfile"
    Failure reason:
    specifiers in the lockfile ({"@douyinfe/semi-ui":"^2.44.0","@react-spring/web":"^9.7.5","@supabase/supabase-js":"^2.38.1","accept-language":"^3.0.18","classes-names":"^1.0.0","emailjs-com":"^3.2.0","i18next":"^23.5.1","i18next-browser-languagedetector":"^7.1.0","i18next-resources-to-backend":"^1.1.4","is-mobile":"^5.0.0","next":"13.5.4","react":"^18","react-dom":"^18","react-google-recaptcha":"^3.1.0","react-i18next":"^13.3.0","swiper":"^11.1.14","tailwind-merge":"^2.5.4","@types/node":"^20","@types/react":"^18","@types/react-dom":"^18","@types/react-google-recaptcha":"^2.1.7","@typescript-eslint/eslint-plugin":"^6.3.0","@typescript-eslint/parser":"^6.3.0","autoprefixer":"^10","eslint":"^8","eslint-config-airbnb":"^19.0.4","eslint-config-airbnb-typescript":"^17.1.0","eslint-config-next":"13.5.4","postcss":"^8","postcss-pxtorem":"^6.1.0","prettier":"^3.3.3","prettier-plugin-tailwindcss":"^0.6.8","tailwindcss":"^3","typescript":"^5"}) don't match specs in package.json ({"@types/node":"^20","@types/react":"^18","@types/react-dom":"^18","@types/react-google-recaptcha":"^2.1.7","@typescript-eslint/eslint-plugin":"^6.3.0","@typescript-eslint/parser":"^6.3.0","autoprefixer":"^10","eslint":"^8","eslint-config-airbnb":"^19.0.4","eslint-config-airbnb-typescript":"^17.1.0","eslint-config-next":"13.5.4","postcss":"^8","postcss-pxtorem":"^6.1.0","prettier":"^3.3.3","prettier-plugin-tailwindcss":"^0.6.8","tailwindcss":"^3","typescript":"^5","@douyinfe/semi-ui":"^2.44.0","@react-spring/web":"^9.7.5","@supabase/supabase-js":"^2.38.1","accept-language":"^3.0.18","bufferutil":"^4.0.8","classes-names":"^1.0.0","emailjs-com":"^3.2.0","i18next":"^23.5.1","i18next-browser-languagedetector":"^7.1.0","i18next-resources-to-backend":"^1.1.4","is-mobile":"^5.0.0","next":"13.5.4","react":"^18","react-dom":"^18","react-google-recaptcha":"^3.1.0","react-i18next":"^13.3.0","swiper":"^11.1.14","tailwind-merge":"^2.5.4","utf-8-validate":"^6.0.5"})
Error: Command "pnpm install" exited with 1

这个错误提示说明 Vercel 在部署过程中使用 pnpm 安装依赖时,遇到了 pnpm-lock.yamlpackage.json 文件中的依赖不匹配问题。具体来说,pnpm-lock.yaml 文件中的依赖版本与 package.json 中声明的版本范围不一致,导致 pnpm 无法继续安装。

看到这时我才意识到我的项目里有个 pnpm-lock.yaml,而我使用的 npm 安装,本地有个 package-lock.json 文件,这样一看是我工具用错了呀,我说这个项目怎么没提交 package-lock.json 文件呢

清理模块重新安装吧

rm -rf .node_modules package-lock.json
pnpm install

输出如下

PS E:\WorkSpace\nodeweb\qxweb> pnpm install

   ╭──────────────────────────────────────────────────────────────────╮
   │                                                                  │
   │                Update available! 9.5.0 → 9.14.2.                 │
   │   Changelog: https://github.com/pnpm/pnpm/releases/tag/v9.14.2   │
   │                Run "pnpm add -g pnpm" to update.                 │
   │                                                                  │
   │         Follow @pnpmjs for updates: https://x.com/pnpmjs         │
   │                                                                  │
   ╰──────────────────────────────────────────────────────────────────╯

Lockfile is up to date, resolution step is skipped
Packages: +423
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 WARN  GET https://registry.npmmirror.com/next/-/next-13.5.4.tgz error (ECONNRESET). Will retry in 10 seconds. 2 retries left.
Downloading @next/swc-win32-x64-msvc@13.5.4: 36.94 MB/36.94 MB, done
Downloading next@13.5.4: 16.80 MB/16.80 MB, done
Downloading typescript@5.2.2: 7.23 MB/7.23 MB, done
Progress: resolved 423, reused 184, downloaded 239, added 423, done
node_modules/.pnpm/es5-ext@0.10.62/node_modules/es5-ext: Running postinstall script, done in 43.1s
node_modules/.pnpm/utf-8-validate@5.0.10/node_modules/utf-8-validate: Running install script, done in 52.3s
node_modules/.pnpm/bufferutil@4.0.8/node_modules/bufferutil: Running install script, done in 52.3s

dependencies:
+ @douyinfe/semi-ui 2.44.0
+ @react-spring/web 9.7.5
+ @supabase/supabase-js 2.38.1
+ accept-language 3.0.18
+ classes-names 1.0.0
+ emailjs-com 3.2.0
+ i18next 23.5.1
+ i18next-browser-languagedetector 7.1.0
+ i18next-resources-to-backend 1.1.4
+ is-mobile 5.0.0
+ next 13.5.4
+ react 18.2.0
+ react-dom 18.2.0
+ react-google-recaptcha 3.1.0
+ react-i18next 13.3.0
+ swiper 11.1.14
+ tailwind-merge 2.5.4

devDependencies:
+ @types/node 20.8.6
+ @types/react 18.2.28
+ @types/react-dom 18.2.13
+ @types/react-google-recaptcha 2.1.7
+ postcss-pxtorem 6.1.0
+ prettier 3.3.3
+ prettier-plugin-tailwindcss 0.6.8
+ tailwindcss 3.3.3
+ typescript 5.2.2

Done in 21m 2.3s

这次再启动项目 pnpm run dev 就不报缺失模块的警告了

简单说下 npmpnpm 的关系,npm 是 Node.js 的默认包管理工具,用于安装、管理和共享 JavaScript 包。安装 Node.js 时会自带 npm,不需要额外安装。pnpm 是一种兼容 npm 和 yarn 的包管理工具。它与 npm 类似,也用来管理 JavaScript 包,但通过优化磁盘使用和依赖解析性能解决了 npm 的一些问题。

再简单说下 package.jsonpackage-lock.jsonpnpm-lock.yaml 的关系

  • package.json 描述项目的基本信息(如项目名称、版本号),声明项目的依赖项、脚本命令和配置,是项目中最重要的依赖描述文件,是开发者直接编辑的文件,但不包含依赖的具体版本信息
  • package-lock.json 是 npm 包管理工具生成的锁定文件,记录依赖的具体版本号和结构,确保不同环境中安装的依赖版本一致。不需要手动编辑,由 npm 自动生成和管理。
  • pnpm-lock.yaml 是 pnpm 包管理工具生成的锁定文件,用于精确记录依赖的版本号和安装结构。确保团队或 CI/CD 环境在安装依赖时,所有人使用的依赖版本完全一致。不需要手动编辑,由 pnpm 自动生成和管理。

可以看到package-lock.jsonpnpm-lock.yaml是互斥的,平时 npmpnpm 选择一个就行,别混着用。

Android问题

Apple推送选择APNs就好了,而Android推送一直就是老大难,因为FCM对谷歌框架的依赖,国内基本是不可用的,所以在之前的蛮荒年代,真是八仙过海各显其能,相互拉起、定时检测等等搞得手机卡顿的不行,后来各家厂商基本都实现了自己的通道,比如华为、小米、OPPO、Vivo等等,所以找个聚合的SDK也是能办到的,但是国外还是主要依赖FCM。

但随着Android版本的提升,推送的要求越来越严,一旦应用被强制杀死,FCM消息虽然能达到手机,但是不允许拉起应用,导致消息无法触及到用户,这也是目前国外环境要实现推送所面临的难点。

要想能收到FCM的推送消息,就得保证应用不被杀死,可能得方向有提高优先级、定时检测重启、杀死后立即重启、采用其他的推送通道等等,但是效果都不理想,之前好用的方式升级版本或者切换一个手机厂商就不太好使了,没有什么通用的解决办法。

后来发现,真对国内手机只要给应用开启自启动权限,那么即使被强杀后也能收到FCM通知,或许这是一个可以努力的方向,但这个权限不是通用的逻辑,每个手机厂商都有自己的白名单,大厂APP出生就在白名单里,而我们自己开发的APP需要经过复杂的引导操作才能加入其中,虽然很难,但终归是第一条可行的路。

主动请求通知权限

在 Android 13 (API 33) 及以上版本,应用需要 主动请求通知权限,以便能够发送通知。对于之前的版本,应用只需要在 AndroidManifest.xml 中声明 POST_NOTIFICATIONS 权限即可。然而,从 Android 13 开始,仅在声明权限的基础上,还需要在运行时申请此权限。

步骤1:修改 AndroidManifest.xml

首先,在 AndroidManifest.xml 文件中声明权限:

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

步骤2:在应用中请求通知权限

从 Android 13 开始,你需要在运行时请求通知权限。你可以使用 NotificationManagerCompat 来检查和请求权限。

import android.os.Build;
import android.widget.Toast;
import androidx.core.app.NotificationManagerCompat;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 检查 Android 13 及以上版本是否需要请求通知权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(this);
            // 检查通知权限是否已被授权
            if (!notificationManagerCompat.areNotificationsEnabled()) {
                // 如果没有授权,可以弹出提示或者引导用户
                requestNotificationPermission();
            } else {
                // 如果已授权,可以继续执行相关逻辑
                Toast.makeText(this, "通知权限已授权", Toast.LENGTH_SHORT).show();
            }
        }
    }

    private void requestNotificationPermission() {
        // 你可以在这里引导用户到设置页面手动授权
        Toast.makeText(this, "请在设置中授权通知权限", Toast.LENGTH_LONG).show();
    }
}

步骤3:引导用户授权

如果用户没有授权通知权限,你通常需要提供一个方法引导他们到设置页面,在该页面中手动授权。因为从 Android 13 开始,权限只能通过系统设置进行手动授权,而不是通过应用内弹窗。

private void goToSettings() {
    Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
            .putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
    startActivity(intent);
}

网络状态变化的监听不能使用静态注册

Android 7.0 (API 24) 开始,网络状态变化的监听不能使用静态注册 (<receiver> 标签在 AndroidManifest.xml 中注册),必须通过动态注册来实现。这是出于优化电池和性能的考虑,Android 不再允许应用通过静态注册的方式来监听系统广播(如网络变化、屏幕开关等),尤其是对敏感的系统事件。

静态注册 (AndroidManifest.xml)

静态注册会在 AndroidManifest.xml 中声明广播接收器,并且会在整个应用运行期间自动接收系统广播。对于网络状态变化(如 CONNECTIVITY_ACTION)的静态注册从 Android 7.0 开始被限制。

AndroidManifest.xml 中的静态注册示例(在 Android 7.0 之前是有效的):

<receiver android:name=".NetworkChangeReceiver">
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
    </intent-filter>
</receiver>

这种方式在 Android 7.0 及以后会被限制,无法接收到网络状态变化的广播。

动态注册 (代码中注册)

动态注册意味着在应用运行时,通过 Context.registerReceiver() 来注册接收器,这样可以选择性地在需要时注册,并在不需要时取消注册。这样做的好处是,可以更灵活地控制接收器的生命周期,避免不必要的电池消耗。

动态注册的示例

public class MainActivity extends AppCompatActivity {
    private NetworkReceiver networkReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化网络广播接收器
        networkReceiver = new NetworkReceiver();
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);

        // 动态注册接收器
        registerReceiver(networkReceiver, filter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 注销接收器
        unregisterReceiver(networkReceiver);
    }
}

public class NetworkReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 获取网络连接状态
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();

        if (activeNetwork != null && activeNetwork.isConnected()) {
            Log.d("NetworkReceiver", "网络已连接");
        } else {
            Log.d("NetworkReceiver", "网络未连接");
        }
    }
}

在这个示例中,使用 registerReceiver() 动态注册了一个监听网络状态变化的广播接收器 NetworkReceiver,并在 onCreate() 中进行注册,在 onDestroy() 中进行注销,以避免内存泄漏。

各种Service介绍和对比

在 Android 中,Service 是一种后台组件,用于在应用中执行长时间运行的任务。根据服务的用途和生命周期,Android 提供了不同类型的服务。以下是 Android 中常见的 Service 类型和 BroadcastReceiver 的介绍及对比:

普通 Service (Normal Service) 没有前台 UI 组件。通常用于执行后台任务,不与用户交互,可以在应用的任何地方启动,并在后台运行,直到它完成工作或被显式停止,生命周期为 onCreate()onStartCommand()onDestroy(),适用执行短时间的后台任务,如数据同步、文件下载等场景。

前台服务 (Foreground Service) 在运行时必须显示一个持续的通知(通知栏),因此它会在用户和系统资源管理中被认为是一个“重要”的服务,不容易被系统杀死。生命周期为 onCreate()onStartCommand()onDestroy() (服务必须调用 startForeground() 来显示通知),适用执行长期任务,如播放音乐、导航、实时更新等场景。

Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
    .setContentTitle("My Foreground Service")
    .setContentText("Service is running in the foreground")
    .setSmallIcon(R.drawable.ic_notification)
    .build();
startForeground(1, notification);

JobService 是一种特殊类型的服务,它用于执行计划任务(即 JobScheduler),在特定条件下(如网络连接、充电等)启动。JobService 适合用于执行延迟任务或条件任务,如周期性数据同步、定时上传等,与 JobScheduler 配合使用,可以在设备的空闲时间或在设备满足某些条件时执行任务。生命周期为 onCreate()onStartJob()onStopJob(),适用执行定期任务,延迟任务,或者需要满足某些条件(如网络连接、充电等)的任务场景

public class MyJobService extends JobService {
    @Override
    public boolean onStartJob(JobParameters params) {
        // 执行任务
        return true; // 返回 true 表示任务正在进行中
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        // 停止任务
        return true; // 返回 true 表示任务被取消
    }
}

BroadcastReceiver 是 Android 中用于接收广播的组件。它通过监听系统广播或自定义广播来响应事件(如网络状态变化、电池电量变化等)。BroadcastReceiver 不会启动一个独立的线程,它只会在接收到广播时执行相应的代码。onReceive() 方法在接收到广播时调用。适用监听和响应系统广播,如网络连接变化、设备开关机、短信接收、系统更新等场景

public class NetworkChangeReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
            // 处理网络变化
        }
    }
}
服务类型生命周期适用场景优缺点
普通 ServiceonCreate()onStartCommand()onDestroy()短时间的后台任务简单易用,但容易被系统杀死,适用于短时间的任务
前台 ForegroundServiceonCreate()onStartCommand()onDestroy()长时间运行的任务,如播放音乐、导航不容易被杀死,但需要显示通知,可能影响用户体验
JobServiceonCreate()onStartJob()onStopJob()执行定期任务、延迟任务,或者需要满足某些条件的任务适用于需要在特定条件下执行的任务,延迟执行,但不能精确控制执行时机
BroadcastReceiveronReceive()响应广播事件,如网络状态变化、电池状态变化等适合处理广播事件,不能执行长时间操作,执行时间受限制

总结

  • Redis如果未使用Jemalloc无法开启主动的碎片回收,通过 redis-cli INFO memory | grep allocator 可查询内存分配器
  • 启动Redis的方法 /usr/local/bin/redis-server ./redis.conf --daemonize yes
  • 管理node模块时可以选择 nmp 或者 pnmp,不要混用,总的来说后者更优秀一点
  • 管理Nextjs项目时最好吧 package.jsonpackage-lock.json(pnpm-lock.yaml)都上传,便于安装出相同的运行环境
  • 触发Vercel重新部署的命令 git commit --allow-empty -m"trigger redeployment"
  • Android的服务有很多种,普通服务Service、前台服务ForegroundService,定时服务JobService等等

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

在自己的世界里独善其身,在别人的世界里顺其自然~

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

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

相关文章

使用C#开发VTK笔记(一)-开发环境搭建

一.使用C#开发VTK的背景 因为C#开发的友好性,一直都比较习惯于从C#开发程序。而长期以来,都希望有一个稳定可靠的三位工程数模的开发演示平台,经过多次对比之后,感觉VTK和OpenCasCade这两个开源项目是比较好的,但它们都是用C++编写的,我用C#形式开发,只能找到发布的C#组…

力扣96:不同的二叉搜索树

给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5示例 2&#xff1a; 输入&#xff1a;n 1 输出&#xff1a;1 卡…

k8s Init:ImagePullBackOff 的解决方法

kubectl describe po (pod名字) -n kube-system 可查看pod所在的节点信息 例如&#xff1a; kubectl describe po calico-node-2lcxx -n kube-system 执行拉取前先把用到的节点的源换了 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF {"re…

人工智能如何改变你的生活?

在我们所处的这个快节奏的世界里&#xff0c;科技融入日常生活已然成为司空见惯的事&#xff0c;并且切实成为了我们生活的一部分。在这场科技变革中&#xff0c;最具变革性的角色之一便是人工智能&#xff08;AI&#xff09;。从我们清晨醒来直至夜晚入睡&#xff0c;人工智能…

道路机器人识别交通灯,马路,左右转,黄线,人行道,机器人等路面导航标志识别-使用YOLO标记

数据集分割 train组66% 268图片 validation集22% 91图片 test集12&#xff05; 48图片 预处理 没有采用任何预处理步骤。 增强 未应用任何增强。 数据集图片&#xff1a; 交通灯 马路 右转 向右掉头 机器人识别 人行横道 黄线 直行或右转 数据集下载&#xff1a; 道路…

【四轴】利用PWM捕获解析接收机信号

在学习这部分之间&#xff0c;建议大家先看之前这篇博客&#xff0c;里面包含对PWM一些重要概念的基本介绍。 【四轴】利用PWM输出驱动无刷电机-CSDN博客 1. 基本原理 1.1 PWM是什么 这一部分可以看我之前的博客&#xff0c;已经对PWM有了基本的介绍。 1.2 什么叫捕获PWM波&…

洛谷 P1162 填涂颜色 C语言 bfs

题目&#xff1a; https://www.luogu.com.cn/problem/P1162 由数字 0 组成的方阵中&#xff0c;有一任意形状的由数字 1 构成的闭合圈。现要求把闭合圈内的所有空间都填写成 22。例如&#xff1a;66的方阵&#xff08;n6&#xff09;&#xff0c;涂色前和涂色后的方阵如下&am…

38 基于单片机的宠物喂食(ESP8266、红外、电机)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52单片机&#xff0c;采用L298N驱动连接P2.3和P2.4口进行电机驱动&#xff0c; 然后串口连接P3.0和P3.1模拟ESP8266&#xff0c; 红外传感器连接ADC0832数模转换器连接单片机的P1.0~P1.…

霍夫变换:原理剖析与 OpenCV 应用实例

简介&#xff1a;本文围绕霍夫变换相关内容展开&#xff0c;先是讲解霍夫变换基本原理&#xff0c;包含从 xy 坐标系到 kb 坐标系及极坐标系的映射等。接着介绍了 cv2.HoughLines、cv2.HoughLinesP 概率霍夫变换、cv2.HoughCircles 霍夫圆变换的函数用法、参数含义、与常规霍夫…

【Debug】hexo-github令牌认证 Support for password authentication was removed

title: 【Debug】hexo-github令牌认证 date: 2024-07-19 14:40:54 categories: bug解决日记 description: “Support for password authentication was removed on August 13, 2021.” cover: https://pic.imgdb.cn/item/669b38ebd9c307b7e9f3e5e0.jpg 第一章 第一篇博客记录一…

JVM 性能调优 -- JVM常用调优工具【jps、jstack、jmap、jstats 命令】

前言&#xff1a; 前面我们分析怎么去预估系统资源&#xff0c;怎么去设置 JVM 参数以及怎么去看 GC 日志&#xff0c;本篇我们分享一些常用的 JVM 调优工具&#xff0c;我们在进行 JVM 调优的时候&#xff0c;通常需要借助一些工具来对系统的进行相关分析&#xff0c;从而确定…

net9 abp vnext 多语言通过数据库动态管理

通过数据库加载实现动态管理&#xff0c;用户可以自己修改界面显示的文本&#xff0c;满足国际化需求 如图所示,前端使用tdesign vnext 新建表TSYS_Localization与TSYS_LocalizationDetail 国旗图标下载网址flag-icons: Free Country Flags in SVG 在Shared下创建下图3个文件 …

Vue:使用 KeepAlive 缓存切换掉的 component

一、内置特殊元素 不是组件 <component>、<slot> 和 <template> 具有类似组件的特性&#xff0c;也是模板语法的一部分。但它们并非真正的组件&#xff0c;同时在模板编译期间会被编译掉。因此&#xff0c;它们通常在模板中用小写字母书写。 1.1 <compone…

Spring中每次访问数据库都要创建SqlSession吗?

一、SqlSession是什么二、源码分析1&#xff09;mybatis获取Mapper流程2&#xff09;Spring创建Mapper接口的代理对象流程3&#xff09;MapperFactoryBean#getObject调用时机4&#xff09;SqlSessionTemplate创建流程5&#xff09;SqlSessionInterceptor拦截逻辑6&#xff09;开…

【数据结构】填空集

基本术语 顺序队列在实现的时候&#xff0c;通常将数组看成是一个首尾相连的循环队列&#xff0c;这样做的目的是为避免产生&#xff08;溢出&#xff09;现象 数组q[M]&#xff08;M等于6&#xff09;存储一个循环队&#xff0c;first和last分别指向首尾指针。已知first2,la…

【趣味升级版】斗破苍穹修炼文字游戏HTML,CSS,JS

目录 图片展示 开始游戏 手动升级&#xff08;满100%即可升级&#xff09; 升级完成&#xff0c;即可解锁打怪模式 新增功能说明&#xff1a; 如何操作&#xff1a; 完整代码 实现一个简单的斗破苍穹修炼文字游戏&#xff0c;你可以使用HTML、CSS和JavaScript结合来构建…

【在Linux世界中追寻伟大的One Piece】多线程(三)

目录 1 -> Linux线程同步 1.1 -> 条件变量 1.2 -> 同步概念与竞态条件 1.3 -> 条件变量函数 1.4 -> 为什么pthread_cond_wait需要互斥量 1.5 -> 条件变量使用规范 2 -> 生产者消费者模型 2.1 -> 为什么要使用生产者消费者模型 2.2 -> 生产…

AI数据分析工具(一)

Looker Studio&#xff08;谷歌&#xff09;-免费 优点 免费使用&#xff1a;对于中小型企业和个人用户来说&#xff0c;没有任何费用压力&#xff0c;可以免费享受到数据可视化和报表创建的功能。与Google服务集成&#xff1a;特别适合使用Google产品生态的企业&#xff0c;…

个人博客接入github issue风格的评论,utteranc,gitment

在做个人博客的时候&#xff0c;如果你需要评论功能&#xff0c;但是又不想构建用户体系和评论模块&#xff0c;那么可以直接使用github的issue提供的接口&#xff0c;对应的开源项目有utteranc和gitment&#xff0c;尤其是前者。 它们的原理是一样的&#xff1a;在博客文章下…

springboot 配置跨域访问

什么是 CORS&#xff1f; CORS&#xff0c;全称是“跨源资源共享”&#xff08;Cross-Origin Resource Sharing&#xff09;&#xff0c;是一种Web应用程序的安全机制&#xff0c;用于控制不同源的资源之间的交互。 在Web应用程序中&#xff0c;CORS定义了一种机制&#xff0…