负载均衡流程

1、负载均衡流程图

2、触发负载均衡函数trigger_load_balance

void trigger_load_balance(struct rq *rq)
{
    /* Don't need to rebalance while attached to NULL domain */
    if (unlikely(on_null_domain(rq)))//当前调度队列中的调度域是空的则返回
        return;

    if (time_after_eq(jiffies, rq->next_balance))//判断下一次均衡的时间是否到
        raise_softirq(SCHED_SOFTIRQ);//触发软中断,在init_sched_fair_class中初始化open_softirq(SCHED_SOFTIRQ, run_rebalance_domains);
#ifdef CONFIG_NO_HZ_COMMON
    if (nohz_kick_needed(rq, false))
        nohz_balancer_kick(false);
#endif
}

2.1 run_rebalance_domains

static __latent_entropy void run_rebalance_domains(struct softirq_action *h)
{
    struct rq *this_rq = this_rq();//获取当前运行队列
    enum cpu_idle_type idle = this_rq->idle_balance ?
                        CPU_IDLE : CPU_NOT_IDLE;//判断当前运行队列是空闲还是非空闲


    /*
     * If this cpu has a pending nohz_balance_kick, then do the
     * balancing on behalf of the other idle cpus whose ticks are
     * stopped. Do nohz_idle_balance *before* rebalance_domains to
     * give the idle cpus a chance to load balance. Else we may
     * load balance only within the local sched_domain hierarchy
     * and abort nohz_idle_balance altogether if we pull some load.
     */
    nohz_idle_balance(this_rq, idle);//给空闲cpu一个均衡的机会进行均衡,
    update_blocked_averages(this_rq->cpu);//更新阻塞平均值
#ifdef CONFIG_NO_HZ_COMMON
    if (!test_bit(NOHZ_STATS_KICK, nohz_flags(this_rq->cpu)))//如果当前cpu设置了NOHZ_STATS_KICK,则跳过,否则进行rebalance_domain
        rebalance_domains(this_rq, idle);
    clear_bit(NOHZ_STATS_KICK, nohz_flags(this_rq->cpu));
#else
    rebalance_domains(this_rq, idle);
#endif
}

2.1.1 nohz_idle_balance

static void nohz_idle_balance(struct rq *this_rq, enum cpu_idle_type idle)
{
    int this_cpu = this_rq->cpu;//获取cpu
    struct rq *rq;
    struct sched_domain *sd;
    int balance_cpu;
    /* Earliest time when we have to do rebalance again */
    unsigned long next_balance = jiffies + 60*HZ;
    int update_next_balance = 0;
#ifdef CONFIG_SPRD_CORE_CTL
    cpumask_t cpus;
#endif

    if (idle != CPU_IDLE ||
        !test_bit(NOHZ_BALANCE_KICK, nohz_flags(this_cpu)))//如果cpu不是空闲,或者设置了NOHZ_BALANCE_KICK,则返回
        goto end;

    /*
     * This cpu is going to update the blocked load of idle CPUs either
     * before doing a rebalancing or just to keep metrics up to date. we
     * can safely update the next update timestamp
     */
    rcu_read_lock();//rcu读锁
    sd = rcu_dereference(this_rq->sd);//获取当前this_rq的调度域
    /*
     * Check whether there is a sched_domain available for this cpu.
     * The last other cpu can have been unplugged since the ILB has been
     * triggered and the sched_domain can now be null. The idle balance
     * sequence will quickly be aborted as there is no more idle CPUs
     */
    if (sd)
        nohz.next_update = jiffies + msecs_to_jiffies(LOAD_AVG_PERIOD);//计算下一次空闲cpu负载均衡的时间
    rcu_read_unlock();


    cpumask_andnot(&cpus, nohz.idle_cpus_mask, cpu_isolated_mask);移除隔离的cpu
    for_each_cpu(balance_cpu, &cpus) {//遍历空闲cpu

        if (balance_cpu == this_cpu || !idle_cpu(balance_cpu))//如果均衡cpu是当前cpu或者不是空闲的,则进行下一个循环。
            continue;

        /*
         * If this cpu gets work to do, stop the load balancing
         * work being done for other cpus. Next load
         * balancing owner will pick it up.
         */
        if (need_resched())//判断如果此cpu需要调度,则停止均衡
            break;

        rq = cpu_rq(balance_cpu);//获取要均衡cpu的运行队列

        /*
         * If time for next balance is due,
         * do the balance.
         */
        if (time_after_eq(jiffies, rq->next_balance)) {//判断均衡时间有没有到
            struct rq_flags rf;

            rq_lock_irq(rq, &rf);//获取运行队列锁
            update_rq_clock(rq);//更新运行队列时钟
            cpu_load_update_idle(rq);//更新队列负载
            rq_unlock_irq(rq, &rf);//释放锁

            update_blocked_averages(balance_cpu);//更新均衡cpu的阻塞平均值
            /*
             * This idle load balance softirq may have been
             * triggered only to update the blocked load and shares
             * of idle CPUs (which we have just done for
             * balance_cpu). In that case skip the actual balance.
             */
            if (!test_bit(NOHZ_STATS_KICK, nohz_flags(this_cpu)))//如果没有设置NOHZ_STATS_KICK,则进行均衡
                rebalance_domains(rq, idle);//域负载均衡
        }

        if (time_after(next_balance, rq->next_balance)) {//更新下一次均衡时间
            next_balance = rq->next_balance;
            update_next_balance = 1;
        }
    }

    /*
     * next_balance will be updated only when there is a need.
     * When the CPU is attached to null domain for ex, it will not be
     * updated.
     */
    if (likely(update_next_balance))//更新下一次均衡时间
        nohz.next_balance = next_balance;
end:
    clear_bit(NOHZ_BALANCE_KICK, nohz_flags(this_cpu));
}

2.2 rebalance_domains函数

static void rebalance_domains(struct rq *rq, enum cpu_idle_type idle)
{
    int continue_balancing = 1;
    int cpu = rq->cpu;
    unsigned long interval;
    struct sched_domain *sd;
    /* Earliest time when we have to do rebalance again */
    unsigned long next_balance = jiffies + 60*HZ;
    int update_next_balance = 0;
    int need_serialize, need_decay = 0;
    u64 max_cost = 0;

    rcu_read_lock();

    for_each_domain(cpu, sd) {//遍历调度域中每个cpu
        /*
         * Decay the newidle max times here because this is a regular
         * visit to all the domains. Decay ~1% per second.
         */
        if (time_after(jiffies, sd->next_decay_max_lb_cost)) {//判断衰减时间有没有到
            sd->max_newidle_lb_cost =
                (sd->max_newidle_lb_cost * 253) / 256;//衰减百分之一
            sd->next_decay_max_lb_cost = jiffies + HZ;//衰减时间更新
            need_decay = 1;
        }
        max_cost += sd->max_newidle_lb_cost;

        if (energy_aware() && !sd_overutilized(sd) && !sd->parent)//在使能了eas且调度域没有过载已及这是个根调度域时跳过
            continue;

        if (!(sd->flags & SD_LOAD_BALANCE)) {//判断此调度域是否设置了SD_LOAD_BALANCE
            if (time_after_eq(jiffies,
                      sd->groups->sgc->next_update))
                update_group_capacity(sd, cpu);//更新cpu调度组能力
            continue;
        }

        /*
         * Stop the load balance at this level. There is another
         * CPU in our sched group which is doing load balancing more
         * actively.
         */
        if (!continue_balancing) {//判断是否停止均衡
            if (need_decay)
                continue;
            break;
        }

        interval = get_sd_balance_interval(sd, idle != CPU_IDLE);//得到调度域的均衡间隔

        need_serialize = sd->flags & SD_SERIALIZE;//判断是否需要串行化
        if (need_serialize) {
            if (!spin_trylock(&balancing))//获取锁
                goto out;
        }

        if (time_after_eq(jiffies, sd->last_balance + interval)) {//判断均衡时间是否到
            if (load_balance(cpu, rq, sd, idle, &continue_balancing)) {//进行均衡
                /*
                 * The LBF_DST_PINNED logic could have changed
                 * env->dst_cpu, so we can't know our idle
                 * state even if we migrated tasks. Update it.
                 */
                idle = idle_cpu(cpu) ? CPU_IDLE : CPU_NOT_IDLE;//获取cpu空闲状态
            }
            sd->last_balance = jiffies;//更新均衡时间
            interval = get_sd_balance_interval(sd, idle != CPU_IDLE);//获取均衡间隔
        }
        if (need_serialize)
            spin_unlock(&balancing);//释放锁
out:
        if (time_after(next_balance, sd->last_balance + interval)) {//判断next_balance是否需要更新
            next_balance = sd->last_balance + interval;
            update_next_balance = 1;
        }
    }
    if (need_decay) {//判断是否需要衰减
        /*
         * Ensure the rq-wide value also decays but keep it at a
         * reasonable floor to avoid funnies with rq->avg_idle.
         */
        rq->max_idle_balance_cost =
            max((u64)sysctl_sched_migration_cost, max_cost);
    }
    rcu_read_unlock();

    /*
     * next_balance will be updated only when there is a need.
     * When the cpu is attached to null domain for ex, it will not be
     * updated.
     */
    if (likely(update_next_balance)) {
        rq->next_balance = next_balance;//更新运行队列下一次均衡时间

#ifdef CONFIG_NO_HZ_COMMON
        /*
         * If this CPU has been elected to perform the nohz idle
         * balance. Other idle CPUs have already rebalanced with
         * nohz_idle_balance() and nohz.next_balance has been
         * updated accordingly. This CPU is now running the idle load
         * balance for itself and we need to update the
         * nohz.next_balance accordingly.
         */
        if ((idle == CPU_IDLE) && time_after(nohz.next_balance, rq->next_balance))//如果cpu状态是空闲且运行队列的下次均衡时间小于空闲cpu的下次均衡时间
            nohz.next_balance = rq->next_balance;//更新空闲cpu的下次均衡时间
#endif
    }
}

2.2.1 load_balance

static int load_balance(int this_cpu, struct rq *this_rq,
            struct sched_domain *sd, enum cpu_idle_type idle,
            int *continue_balancing)
{
    int ld_moved, cur_ld_moved, active_balance = 0;
    struct sched_domain *sd_parent = lb_sd_parent(sd) ? sd->parent : NULL;
    struct sched_group *group;
    struct rq *busiest;
    struct rq_flags rf;
    struct cpumask *cpus = this_cpu_cpumask_var_ptr(load_balance_mask);

    

struct lb_env env = {//负载平衡环境,包含了一组与负载平衡相关的参数和状态信息
        .sd        = sd,//调度域
        .dst_cpu    = this_cpu,//均衡给此cpu
        .dst_rq        = this_rq,//均衡给此队列
        .dst_grpmask    = sched_group_span(sd->groups),//目标调度组掩码
        .idle        = idle,//cpu状态
        .loop_break    = sched_nr_migrate_break,//迁移间隔
        .cpus        = cpus,
        .fbq_type    = all,
        .tasks        = LIST_HEAD_INIT(env.tasks),
    };

    cpumask_and(cpus, sched_domain_span(sd), cpu_active_mask);//将调度域中处于active状态的cpu挑选出来

    schedstat_inc(sd->lb_count[idle]);//更新负载均衡idle类型的计数

redo:
    if (!should_we_balance(&env)) {//判断是否应该均衡
        *continue_balancing = 0;
        goto out_balanced;
    }

    group = find_busiest_group(&env);//找到最繁忙的组
    if (!group) {
        schedstat_inc(sd->lb_nobusyg[idle]);
        goto out_balanced;
    }

    busiest = find_busiest_queue(&env, group);//找到最繁忙的队列
    if (!busiest) {
        schedstat_inc(sd->lb_nobusyq[idle]);
        goto out_balanced;
    }

    BUG_ON(busiest == env.dst_rq);//最繁忙的队列不等于目的队列

    schedstat_add(sd->lb_imbalance[idle], env.imbalance);更新负载均衡idle类型不均衡的计数

    env.src_cpu = busiest->cpu;//最繁忙的队列的cpu给要均衡的cpu
    env.src_rq = busiest;//最繁忙的队列给要均衡的队列

    ld_moved = 0;
    if (busiest->nr_running > 1) {最繁忙的运行队列中的task要大于1
        /*
         * Attempt to move tasks. If find_busiest_group has found
         * an imbalance but busiest->nr_running <= 1, the group is
         * still unbalanced. ld_moved simply stays zero, so it is
         * correctly treated as an imbalance.
         */
        env.flags |= LBF_ALL_PINNED;
        env.loop_max  = min(sysctl_sched_nr_migrate, busiest->nr_running);//最大循环的次数

more_balance:
        rq_lock_irqsave(busiest, &rf);//获取锁
        update_rq_clock(busiest);//更新最忙的队列的时钟

        /*
         * cur_ld_moved - load moved in current iteration
         * ld_moved     - cumulative load moved across iterations
         */
        cur_ld_moved = detach_tasks(&env, &rf);//出队,将要迁移的task从src cpu中移除并返回出队的个数

        /*
         * We've detached some tasks from busiest_rq. Every
         * task is masked "TASK_ON_RQ_MIGRATING", so we can safely
         * unlock busiest->lock, and we are able to be sure
         * that nobody can manipulate the tasks in parallel.
         * See task_rq_lock() family for the details.
         */

        rq_unlock(busiest, &rf);//释放锁

        if (cur_ld_moved) {
            attach_tasks(&env);//入队,将移除的task加入到新的队列中
            ld_moved += cur_ld_moved;
        }

        local_irq_restore(rf.flags);//恢复本地的中断状态

        if (env.flags & LBF_NEED_BREAK) {//判断是否设置了LBF_NEED_BREAK
            env.flags &= ~LBF_NEED_BREAK;
            goto more_balance;
        }

        /*
         * Revisit (affine) tasks on src_cpu that couldn't be moved to
         * us and move them to an alternate dst_cpu in our sched_group
         * where they can run. The upper limit on how many times we
         * iterate on same src_cpu is dependent on number of cpus in our
         * sched_group.
         *
         * This changes load balance semantics a bit on who can move
         * load to a given_cpu. In addition to the given_cpu itself
         * (or a ilb_cpu acting on its behalf where given_cpu is
         * nohz-idle), we now have balance_cpu in a position to move
         * load to given_cpu. In rare situations, this may cause
         * conflicts (balance_cpu and given_cpu/ilb_cpu deciding
         * _independently_ and at _same_ time to move some load to
         * given_cpu) causing exceess load to be moved to given_cpu.
         * This however should not happen so much in practice and
         * moreover subsequent load balance cycles should correct the
         * excess load moved.
         */
        if ((env.flags & LBF_DST_PINNED) && env.imbalance > 0) {//果sched domain仍然未达均衡均衡状态,并且在之前的均衡过程中,有因为affinity的原因导致任务无法迁移到dest cpu,这时候要继续在src rq上搜索任务,迁移到备选的dest cpu,因此,这里再次发起均衡操作。这里的均衡上下文的dest cpu设定为备选的cpu,loop也被清零,重新开始扫描。

            /* Prevent to re-select dst_cpu via env's cpus */
            cpumask_clear_cpu(env.dst_cpu, env.cpus);

            env.dst_rq     = cpu_rq(env.new_dst_cpu);//备用cpu队列
            env.dst_cpu     = env.new_dst_cpu;
            env.flags    &= ~LBF_DST_PINNED;
            env.loop     = 0;
            env.loop_break     = sched_nr_migrate_break;

            /*
             * Go back to "more_balance" rather than "redo" since we
             * need to continue with same src_cpu.
             */
            goto more_balance;
        }

        /*
         * We failed to reach balance because of affinity.
         */
        if (sd_parent) {//如果父调度域存在
            int *group_imbalance = &sd_parent->groups->sgc->imbalance;

            if ((env.flags & LBF_SOME_PINNED) && env.imbalance > 0)//由于亲和性原因不能在目标cpu上迁移而设置了LBF_SOME_PINNED
                *group_imbalance = 1;
        }

        /* All tasks on this runqueue were pinned by CPU affinity */
        if (unlikely(env.flags & LBF_ALL_PINNED)) {//设置了LBF_ALL_PINNED,由于亲和性原因在这个运行队列上的所有的任务不能迁移
            cpumask_clear_cpu(cpu_of(busiest), cpus);//清除在cpus中的busiest所在的cpu
            /*
             * Attempting to continue load balancing at the current
             * sched_domain level only makes sense if there are
             * active CPUs remaining as possible busiest CPUs to
             * pull load from which are not contained within the
             * destination group that is receiving any migrated
             * load.
             */
            if (!cpumask_subset(cpus, env.dst_grpmask)) {//如果选中的busiest cpu上的任务全部都是通过affinity锁定在了该cpu上,那么清除该cpu(为了确保下轮均衡不考虑该cpu),再次发起均衡。这种情况下,需要重新搜索source cpu,因此跳转到redo
                env.loop = 0;
                env.loop_break = sched_nr_migrate_break;
                goto redo;
            }
            goto out_all_pinned;
        }
    }

    if (!ld_moved) {//如果前面迁移的task如果为0,则走这里
        schedstat_inc(sd->lb_failed[idle]);//增加负载均衡lb_failed计数
        /*
         * Increment the failure counter only on periodic balance.
         * We do not want newidle balance, which can be very
         * frequent, pollute the failure counter causing
         * excessive cache_hot migrations and active balances.
         */
        if (idle != CPU_NEWLY_IDLE)//如果cpu状态不是刚刚处于空闲状态
            if (env.src_grp_nr_running > 1)//要迁移的调度组中的队列个数大于1
                sd->nr_balance_failed++;//失败计数加一

        if (need_active_balance(&env)) {//判断是否要启动active balance。所谓activebalance就是把当前正在运行的任务迁移到dest cpu上。也就是说经过前面一番折腾,runnable的任务都无法迁移到dest cpu,从而达到均衡,那么就考虑当前正在运行的任务
            unsigned long flags;

            raw_spin_lock_irqsave(&busiest->lock, flags);

            /* don't kick the active_load_balance_cpu_stop,
             * if the curr task on busiest cpu can't be
             * moved to this_cpu
             */
            if (!cpumask_test_cpu(this_cpu, &busiest->curr->cpus_allowed)) {//在启动active balance之前,先看看busiestcpu上当前正在运行的任务是否可以运行在dest cpu上。如果不可以的话,那么不再试图执行均衡操作,跳转到out_one_pinned
                raw_spin_unlock_irqrestore(&busiest->lock,
                                flags);
                env.flags |= LBF_ALL_PINNED;
                goto out_one_pinned;
            }

            /*
             * ->active_balance synchronizes accesses to
             * ->active_balance_work.  Once set, it's cleared
             * only after active load balance is finished.
             */
#ifdef CONFIG_SPRD_CORE_CTL
            if (!busiest->active_balance &&
                !cpu_isolated(cpu_of(busiest))) {
#else
            if (!busiest->active_balance) {//busiest cpu运行队列上设置active balance的标记
#endif
                busiest->active_balance = 1;
                busiest->push_cpu = this_cpu;
                active_balance = 1;
            }
            raw_spin_unlock_irqrestore(&busiest->lock, flags);

            if (active_balance) {//将正在运行的busiest cpu 正在运行的任务停止并进行迁移
                stop_one_cpu_nowait(cpu_of(busiest),
                    active_load_balance_cpu_stop, busiest,
                    &busiest->active_balance_work);
            }

            /* We've kicked active balancing, force task migration. */
            sd->nr_balance_failed = sd->cache_nice_tries+1;
        }
    } else
        sd->nr_balance_failed = 0;//完成了至少一个任务迁移

    if (likely(!active_balance)) {
        /* We were unbalanced, so reset the balancing interval */
        sd->balance_interval = sd->min_interval;//重新设置均衡间隔
    } else {
        /*
         * If we've begun active balancing, start to back off. This
         * case may not be covered by the all_pinned logic if there
         * is only 1 task on the busy runqueue (because we don't call
         * detach_tasks).
         */
        if (sd->balance_interval < sd->max_interval)
            sd->balance_interval *= 2;
    }

    goto out;

out_balanced:
    /*
     * We reach balance although we may have faced some affinity
     * constraints. Clear the imbalance flag if it was set.
     */
    if (sd_parent) {
        int *group_imbalance = &sd_parent->groups->sgc->imbalance;

        if (*group_imbalance)
            *group_imbalance = 0;
    }

out_all_pinned://由于所有的亲和性原因
    /*
     * We reach balance because all tasks are pinned at this level so
     * we can't migrate them. Let the imbalance flag set so parent level
     * can try to migrate them.
     */
    schedstat_inc(sd->lb_balanced[idle]);

    sd->nr_balance_failed = 0;

out_one_pinned://由某个task亲和性原因
    ld_moved = 0;

    /*
     * idle_balance() disregards balance intervals, so we could repeatedly
     * reach this code, which would lead to balance_interval skyrocketting
     * in a short amount of time. Skip the balance_interval increase logic
     * to avoid that.
     */
    if (env.idle == CPU_NEWLY_IDLE)
        goto out;

    /* tune up the balancing interval */
    if (((env.flags & LBF_ALL_PINNED) &&
            sd->balance_interval < MAX_PINNED_INTERVAL) ||
            (sd->balance_interval < sd->max_interval))
        sd->balance_interval *= 2;
out:
    return ld_moved;
}

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

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

相关文章

【嵌入式学习】C++QT-Day1-C++基础

思维导图&&笔记 见我的博客&#xff1a;https://lingjun.life/wiki/EmbeddedNote/19Cpp 作业&#xff1a; 提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数 要求使用C风格字符串完成 #include <iostream&…

[MRCTF2020]Ez_bypass1

代码审计&#xff0c;要求gg和id的MD5值相等而gg和id的值不等或类型不等 相同MD5值的不同字符串_md5相同的不同字符串-CSDN博客 不过这道题好像只能用数组 下一步是passwd不能是纯数字&#xff0c;但是下一个判断又要passwd等于1234567 这里通过passwd1234567a实现绕过 原…

3D点云数据的标定,从搭建环境到点云标定方法及过程,只要有一台Windows笔记本,让你学会点云标定

ptscloudpre: 点云标定准备&#xff1a; 说明&#xff1a; 如下介绍适用windows系统的电脑。apple笔记本同理&#xff0c;但是需要安装MAC版本的anaconda。网址&#xff1a;Free Download | Anaconda可下载对应MAC版本的Anaconda的安装包建议下载2022年或2021年的安装包安装。…

qml中访问控件内部的子项

如何访问Repeater类型内部的子项、Row等布局类型内部的子项以及ListView内部的子项等。。。 1、测试代码 import QtQuick 2.0 import QtQuick.Controls 2.12 import QtQuick.Window 2.12 import QtQuick.Layouts 1.3 import QtQml 2.12Window {id: windowobjectName: "m…

基于Python Django的大数据招聘数据分析系统,包括数据大屏和后台管理

基于Python Django的大数据招聘数据分析系统是一个综合利用大数据技术和数据可视化技术的招聘行业解决方案。该系统旨在帮助企业和招聘机构更好地理解和分析招聘市场的趋势和变化&#xff0c;从而提高招聘效率和质量。 首先&#xff0c;该系统提供了一个强大的后台管理功能&am…

Docker容器引擎(3)

目录 一.Docker 镜像的创建 1&#xff0e;基于现有镜像创建 2&#xff0e;基于本地模板创建 3.基于Dockerfile创建&#xff1a; Dockerfile 操作常用的指令&#xff1a; ADD 和 COPY 的区别&#xff1f; CMD 和 ENTRYPOINT 的区别&#xff1f; 容器启动命令的优先级 如…

前端vue集成echarts图形报表样例

文章目录 &#x1f412;个人主页&#x1f3c5;Vue项目常用组件模板仓库&#x1f4d6;前言&#xff1a;&#x1f415;1.在项目终端下载echarts依赖包&#x1f3e8;2.在main.js中导入echarts资源包并使用&#x1f380;3.在.vue文件中直接使用echarts&#xff0c;下面是一个样例&a…

[设计模式Java实现附plantuml源码~创建型] 产品族的创建——抽象工厂模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

C语言-算法-线性dp

[USACO1.5] [IOI1994]数字三角形 Number Triangles 题目描述 观察下面的数字金字塔。 写一个程序来查找从最高点到底部任意处结束的路径&#xff0c;使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。 在上面的样例中&#xff0c;从 7 → 3 → 8 →…

yolov8上使用gpu教程

yolov8上使用gpu教程 安装Cuda和Cudnnyolov8上使用gpu 安装Cuda和Cudnn 1.查看支持的cuda版本&#xff0c;并去官网下载。 nvidia-smi2.网址&#xff1a;https://developer.nvidia.com/cuda-toolkit-archive 3.安装细节 安装的前提基础是&#xff0c;有vs的C环境。我电脑有…

开始学习Vue2(组件的生命周期和数据共享)

一、组件的生命周期 1. 生命周期 & 生命周期函数 生命周期&#xff08;Life Cycle&#xff09;是指一个组件从创建 -> 运行 -> 销毁的整个阶段&#xff0c;强调的是一个时间段。 生命周期函数&#xff1a;是由 vue 框架提供的内置函数&#xff0c;会伴随着 组件…

必知的量化交易基础

量化交易核心概念 量化思想 量化交易 量化交易是指以先进的数学模型代替人为的主观判断&#xff0c;利用计算机技术从庞大的历史数据中海选能带来超额收益的多种“大概率”事件以制定策略&#xff0c;极大地减少了投资者情绪波动的影响&#xff0c;避免在市场极度狂热或悲观的…

对Git更深入了解与学习

对Git更深入了解与学习 0. 前言0.1 工作区与暂存区 1. git remote update origin2. git push origin --delete 分支名 删除远端分支3. git remote4. git fetch5. git status5.1 git status 直观理解5.2 暂存与暂存取消 &#xff08;git restore&#xff09;5.3 push之后 6. git…

SpringBootAdmin邮件通知

在上一篇中我们学习到了 Admin Service Clustering 分布式缓存配置 &#xff0c;这一篇我们来学习&#xff0c;客户端离线&#xff0c;出现故障的时候&#xff0c;我们这么能及时知道呢&#xff0c;发现邮件通知也许是最简单的方式了&#xff01; 邮件通知 邮件通知将作为使用…

Linux文本编辑器-vi/vim

一.vi/vim编辑器介绍 vi\vim是visual interface的简称, 是Linux中最经典的文本编辑器 同图形化界面中的 文本编辑器一样&#xff0c;vi是命令行下对文本文件进行编辑的绝佳选择。 vim 是 vi 的加强版本&#xff0c;兼容 vi 的所有指令&#xff0c;不仅能编辑文本&#xff0c;而…

哈希的基本概念(开散列和闭散列)(附代码)

哈希 哈希概念哈希冲突哈希函数常见的哈希函数 哈希冲突的解决闭散列开散列 哈希概念 传统的查找函数&#xff0c;搜索的效率取决于比较的次数。而hash算法&#xff1a;在理想情况下&#xff0c;可以不经过任何比较&#xff0c;一次就能得到要搜索的结果。 存储结构&#xff1…

面向社交网络语言隐写分析

论文&#xff1a;Linguistic Steganalysis Toward Social Network 发表在&#xff1a;IEEE Transactions on Information Forensics & Security是网络与信息安全领域的国际两大顶级期刊之一&#xff0c;中国计算机学会&#xff08;CCF&#xff09;推荐的A类期刊&#xff0c…

​用技术的视角,去看一台家用 MPV 该有的水准

「MPV」一个在 2023 年之前都属于「小众」车型的品类。 但从 2023 年初开始&#xff0c;MPV 却变成了新能源&#xff0c;特别是高端新能源品牌必争的细分产品。 从岚图推梦想家开始&#xff0c;到腾势 D9&#xff0c;再到极氪 009&#xff0c;最后到魏牌高山&#xff0c;标志…

【开源】基于JAVA语言的智慧社区业务综合平台

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 业务类型模块2.2 基础业务模块2.3 预约业务模块2.4 反馈管理模块2.5 社区新闻模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 业务类型表3.2.2 基础业务表3.2.3 预约业务表3.2.4 反馈表3.2.5 社区新闻表 四、系统展…

Java中的this和super

①this 在Java中&#xff0c;this关键字代表当前对象的引用。它可以用于以下几个方面&#xff1a; 引用当前对象的成员变量&#xff1a;使用this关键字可以引用当前对象的成员变量&#xff0c;以区分成员变量和方法参数或局部变量之间的命名冲突。例如&#xff0c;如果一个方法…