后端要一次性返回我10万条数据

news2024/11/22 23:26:14

问题描述

  • 面试官:后端一次性返回10万条数据给你,你如何处理?
  • 我:歪嘴一笑,what the f**k!

问题考察点

看似无厘头的问题,实际上考查候选人知识的广度和深度,虽然在工作中这种情况很少遇到...

  • 考察前端如何处理大量数据
  • 考察候选人对于大量数据的性能优化
  • 考察候选人处理问题的思考方式(关于这一点,文末会说到,大家继续阅读)
  • ......

文末会提供完整代码,供大家更好的理解

使用express创建一个十万条数据的接口

若是道友对express相关不太熟悉的话,有空可以看看笔者的这一篇全栈文章(还有完整代码哦):《Vue+Express+Mysql全栈项目之增删改查、分页排序导出表格功能》

route.get("/bigData", (req, res) => {
  res.header('Access-Control-Allow-Origin', '*'); // 允许跨域
  let arr = [] // 定义数组,存放十万条数据
  for (let i = 0; i < 100000; i++) { // 循环添加十万条数据
    arr.push({
      id: i + 1,
      name: '名字' + (i + 1),
      value: i + 1,
    })
  }
  res.send({ code: 0, msg: '成功', data: arr }) // 将十万条数据返回之
})
复制代码

点击按钮,发请求,获取数据,渲染到表格上

html结构如下:

<el-button :loading="loading" @click="plan">点击请求加载</el-button>

<el-table :data="arr">
  <el-table-column type="index" label="序" />
  <el-table-column prop="id" label="ID" />
  <el-table-column prop="name" label="名字" />
  <el-table-column prop="value" label="对应值" />
</el-table>

data() {
    return {
      arr: [],
      loading: false,
    };
},

async plan() {
    // 发请求,拿数据,赋值给arr
}
复制代码

方案一 直接渲染所有数据

如果请求到10万条数据直接渲染,页面会卡死的,很显然,这种方式是不可取的

 async plan() {
      this.loading = true;
      const res = await axios.get("http://ashuai.work:10000/bigData");
      this.arr = res.data.data;
      this.loading = false;
}
复制代码

方案二 使用定时器分组分批分堆依次渲染(定时加载、分堆思想)

  • 正常来说,十万条数据请求,需要2秒到10秒之间(有可能更长,取决于数据具体内容)
  • 而这种方式就是,前端请求到10万条数据以后,先不着急渲染,先将10万条数据分堆分批次
  • 比如一堆存放10条数据,那么十万条数据就有一万堆
  • 使用定时器,一次渲染一堆,渲染一万次即可
  • 这样做的话,页面就不会卡死了

用户所看到的效果图是如下

效果图

分组分批分堆函数

  • 我们先写一个函数,用于将10万条数据进行分堆
  • 所谓的分堆其实思想就是一次截取一定长度的数据
  • 比如一次截取10条数据,头一次截取0~9,第二次截取10~19等固定长度的截取
  • 举例原来的数据是:[1,2,3,4,5,6,7]
  • 假设我们分堆以后,一堆分3个,那么得到的结果就是二维数组了
  • 即:[ [1,2,3], [4,5,6], [7]]
  • 然后就遍历这个二维数组,得到每一项的数据,即为每一堆的数据
  • 进而使用定时器一点点、一堆堆赋值渲染即可

分组分批分堆函数(一堆分10个)

function averageFn(arr) {
  let i = 0; // 1. 从第0个开始截取
  let result = []; // 2. 定义结果,结果是二维数组
  while (i < arr.length) { // 6. 当索引等于或者大于总长度时,即截取完毕
    // 3. 从原始数组的第一项开始遍历
    result.push(arr.slice(i, i + 10)); // 4. 在原有十万条数据上,一次截取10个用于分堆
    i = i + 10; // 5. 这10条数据截取完,再截取下十条数据,以此类推
  }
  return result; // 7. 最后把结果丢出去即可
}
复制代码

创建定时器去依次赋值渲染

比如我们每隔一秒钟去赋值渲染一次

  async plan() {
      this.loading = true;
      const res = await axios.get("http://ashuai.work:10000/bigData");
      this.loading = false;
      let twoDArr = averageFn(res.data.data);
      for (let i = 0; i < twoDArr.length; i++) {
        // 相当于在很短的时间内创建许多个定时任务去处理
        setTimeout(() => {
          this.arr = [...this.arr, ...twoDArr[i]]; // 赋值渲染
        }, 1000 * i); // 17 * i // 注意设定的时间间隔... 17 = 1000 / 60
      }
    },
复制代码

这种方式,相当于在很短的时间内创建许多个定时任务去处理,定时任务太多了,也耗费资源啊。

实际上,这种方式就有了大数据量分页的思想

方案三 使用requestAnimationFrame替代定时器去做渲染

关于requestAnimationFrame定时器优点,道友们可以看笔者的这篇文章:《性能优化之通俗易懂学习requestAnimationFrame和使用场景举例》

反正大家遇到定时器的时候,就可以考虑一下,是否可以使用请求动画帧进行优化执行渲染?

如果使用请求动画帧的话,就要修改一下代码写法了,前面的不变化,plan方法中的写法变一下即可,注意注释:

async plan() {
  this.loading = true;
  const res = await axios.get("http://ashuai.work:10000/bigData");
  this.loading = false;
  // 1. 将大数据量分堆
  let twoDArr = averageFn(res.data.data);
  // 2. 定义一个函数,专门用来做赋值渲染(使用二维数组中的每一项)
  const use2DArrItem = (page) => {
    // 4. 从第一项,取到最后一项
    if (page > twoDArr.length - 1) {
      console.log("每一项都获取完了");
      return;
    }
    // 5. 使用请求动画帧的方式
    requestAnimationFrame(() => {
      // 6. 取出一项,就拼接一项(concat也行)
      this.arr = [...this.arr, ...twoDArr[page]];
      // 7. 这一项搞定,继续下一项
      page = page + 1;
      // 8. 直至完毕(递归调用,注意结束条件)
      use2DArrItem(page);
    });
  };
  // 3. 从二维数组中的第一项,第一堆开始获取并渲染(数组的第一项即索引为0)
  use2DArrItem(0); 
},
复制代码

方案四 搭配分页组件,前端进行分页(每页展示一堆,分堆思想)

这种方式,笔者曾经遇到过,当时的对应场景是数据量也就几十条,后端直接把几十条数据丢给前端,让前端去分页

后端不做分页的原因是。他当时临时有事情请假了,所以就前端去做分页了。

  • 数据量大的情况下,这种方式,也是一种解决方案
  • 思路也是在所有数据的基础上进行截取
  • 简要代码如下:
getShowTableData() { 
    // 获取截取开始索引 
    let begin = (this.pageIndex - 1) * this.pageSize; 
    // 获取截取结束索引
     let end = this.pageIndex * this.pageSize; 
    // 通过索引去截取,从而展示
    this.showTableData = this.allTableData.slice(begin, end); 
}
复制代码

完整案例代码,请看笔者的这篇文章:《后端一次性返回所有的数据,让前端截取展示做分页》

实际上,这种大任务拆分成许多小任务,这种方式,做法,应用的思想就是分片的方式(时间),在别的场景,比如大文件上传的时候,也有这种思想,比如一个500MB的大文件,拆分成50个小文件,一个是10MB这样...至于大文件上传的文章,那就等笔者有空了再写呗...

方案五 表格滚动触底加载(滚动到底,再加载一堆)

这里重点就是我们需要去判断,何时滚动条触底。判断方式主要有两种

  • scrollTop + clientHeight >= innerHeight
  • new MutationObserver()去观测

目前市面上主流的一些插件的原理,大致是这两种。

笔者举例的这是,是使用的插件v-el-table-infinite-scroll,本质上这个插件是一个自定义指令。对应npm地址:www.npmjs.com/package/el-…

当然也有别的插件,如vue-scroller 等:一个意思,不赘述

注意,触底加载也是要分堆的,将发请求获取到的十万条数据,进行分好堆,然后每触底一次,就加载一堆即可

在el-table中使用el-table-infinite-scroll指令步骤

安装,注意版本号(区分vue2和vue3)

cnpm install --save el-table-infinite-scroll@1.0.10

注册使用指令插件

// 使用无限滚动插件
import elTableInfiniteScroll from 'el-table-infinite-scroll';
Vue.use(elTableInfiniteScroll);
复制代码

因为是一个自定义指令,所以直接写在el-table标签上即可

<el-table
  v-el-table-infinite-scroll="load"
  :data="tableData"
>
  <el-table-column prop="id" label="ID"></el-table-column>
  <el-table-column prop="name" label="名字"></el-table-column>
</el-table>

async load() {
    // 触底加载,展示数据...
},
复制代码

案例代码

为了方便大家演示,这里笔者直接附上一个案例代码,注意看其中的步骤注释即可

<template>
  <div class="box">
    <el-table
      v-el-table-infinite-scroll="load"
      height="600"
      :data="tableData"
      border
      style="width: 80%"
      v-loading="loading"
      element-loading-text="数据量太大啦,客官稍后..."
      element-loading-spinner="el-icon-loading"
      element-loading-background="rgba(255, 255, 255, 0.5)"
      :header-cell-style="{
        height: '24px',
        lineHeight: '24px',
        color: '#606266',
        background: '#F5F5F5',
        fontWeight: 'bold',
      }"
    >
      <el-table-column type="index" label="序"></el-table-column>
      <el-table-column prop="id" label="ID"></el-table-column>
      <el-table-column prop="name" label="名字"></el-table-column>
      <el-table-column prop="value" label="对应值"></el-table-column>
    </el-table>
  </div>
</template>

<script>
// 分堆函数
function averageFn(arr) {
  let i = 0;
  let result = [];
  while (i < arr.length) {
    result.push(arr.slice(i, i + 10)); // 一次截取10个用于分堆
    i = i + 10; // 这10个截取完,再准备截取下10个
  }
  return result;
}
import axios from "axios";
export default {
  data() {
    return {
      allTableData: [], // 初始发请求获取所有的数据
      tableData: [], // 要展示的数据
      loading: false
    };
  },
  // 第一步,发请求,获取大量数据,并转成二维数组,分堆分组分块存储
  async created() {
    this.loading = true;
    const res = await axios.get("http://ashuai.work:10000/bigData");
    this.allTableData = averageFn(res.data.data); // 使用分堆函数,存放二维数组
    // this.originalAllTableData = this.allTableData // 也可以存一份原始值,留作备用,都行的
    this.loading = false;
    // 第二步,操作完毕以后,执行触底加载方法
    this.load(); 
  },
  methods: {
    // 初始会执行一次,当然也可以配置,使其不执行
    async load() {
      console.log("自动多次执行之,首次执行会根据高度去计算要执行几次合适");
      // 第五步,触底加载相当于把二维数组的每一项取出来用,取完用完时return停止即可
      if (this.allTableData.length == 0) {
        console.log("没数据啦");
        return;
      }
      // 第三步,加载的时候,把二维数组的第一项取出来,拼接到要展示的表格数据中去
      let arr = this.allTableData[0];
      this.tableData = this.tableData.concat(arr);
      // 第四步,拼接展示以后,再把二维数组的第一项的数据删除即可
      this.allTableData.shift();
    },
  },
};
</script>
复制代码

效果图

方案六 使用无限加载/虚拟列表进行展示

什么是虚拟列表?

  • 所谓的虚拟列表实际上是前端障眼法的一种表现形式。
  • 看到的好像所有的数据都渲染了,实际上只渲染可视区域的部分罢了
  • 有点像我们看电影,我们看的话,是在一块电影屏幕上,一秒一秒的看(不停的放映)
  • 但是实际上电影有俩小时,如果把两个小时的电影都铺开的话,那得需要多少块电影屏幕呢?
  • 同理,如果10万条数据都渲染,那得需要多少dom节点元素呢?
  • 所以我们只给用户看,他当下能看到的
  • 如果用户要快进或快退(下拉滚动条或者上拉滚动条)
  • 再把对应的内容呈现在电影屏幕上(呈现在可视区域内)
  • 这样就实现了看着像是所有的dom元素每一条数据都有渲染的障眼法效果了

关于前端障眼法,在具体工作中,如果能够巧妙使用,会大大提升我们的开发效率的

写一个简单的虚拟列表

效果图

这里笔者直接上代码,大家复制粘贴即可使用,笔者写了一些注释,以便于大家理解。当然也可以去笔者的仓库中去瞅瞅哦,GitHub仓库在文末

代码

<template>
  <!-- 虚拟列表容器,类似“窗口”,窗口的高度取决于一次展示几条数据
            比如窗口只能看到10条数据,一条40像素,10条400像素
            故,窗口的高度为400像素,注意要开定位和滚动条 -->
  <div
    class="virtualListWrap"
    ref="virtualListWrap"
    @scroll="handleScroll"
    :style="{ height: itemHeight * count + 'px' }"
  >
    <!-- 占位dom元素,其高度为所有的数据的总高度 -->
    <div
      class="placeholderDom"
      :style="{ height: allListData.length * itemHeight + 'px' }"
    ></div>
    <!-- 内容区,展示10条数据,注意其定位的top值是变化的 -->
    <div class="contentList" :style="{ top: topVal }">
      <!-- 每一条(项)数据 -->
      <div
        v-for="(item, index) in showListData"
        :key="index"
        class="itemClass"
        :style="{ height: itemHeight + 'px' }"
      >
        {{ item.name }}
      </div>
    </div>
    <!-- 加载中部分 -->
    <div class="loadingBox" v-show="loading">
      <i class="el-icon-loading"></i>
      &nbsp;&nbsp;<span>loading...</span>
    </div>
  </div>
</template>
<script>
import axios from "axios";
export default {
  data() {
    return {
      allListData: [], // 所有的数据,比如这个数组存放了十万条数据
      itemHeight: 40, // 每一条(项)的高度,比如40像素
      count: 10, // 一屏展示几条数据
      start: 0, // 开始位置的索引
      end: 10, // 结束位置的索引
      topVal: 0, // 父元素滚动条滚动,更改子元素对应top定位的值,确保联动
      loading: false,
    };
  },
  computed: {
    // 从所有的数据allListData中截取需要展示的数据showListData
    showListData: function () {
      return this.allListData.slice(this.start, this.end);
    },
  },
  async created() {
    this.loading = true;
    const res = await axios.get("http://ashuai.work:10000/bigData");
    this.allListData = res.data.data;
    this.loading = false;
  },
  methods: {
    // 滚动这里可以加上节流,减少触发频次
    handleScroll() {
      /**
       * 获取在垂直方向上,滚动条滚动了多少像素距离Element.scrollTop
       *
       * 滚动的距离除以每一项的高度,即为滚动到了多少项,当然,要取个整数
       * 例:滚动4米,一步长0.8米,滚动到第几步,4/0.8 = 第5步(取整好计算)
       *
       * 又因为我们一次要展示10项,所以知道了起始位置项,再加上结束位置项,
       * 就能得出区间了【起始位置, 起始位置 + size项数】==【起始位置, 结束位置】
       * */
      const scrollTop = this.$refs.virtualListWrap.scrollTop;
      this.start = Math.floor(scrollTop / this.itemHeight);
      this.end = this.start + this.count;
      /**
       * 动态更改定位的top值,确保联动,动态展示相应内容
       * */
      this.topVal = this.$refs.virtualListWrap.scrollTop + "px";
    },
  },
};
</script>
<style scoped lang="less">
// 虚拟列表容器盒子
.virtualListWrap {
  box-sizing: border-box;
  width: 240px;
  border: solid 1px #000000;
  // 开启滚动条
  overflow-y: auto;
  // 开启相对定位
  position: relative;
  .contentList {
    width: 100%;
    height: auto;
    // 搭配使用绝对定位
    position: absolute;
    top: 0;
    left: 0;
    .itemClass {
      box-sizing: border-box;
      width: 100%;
      height: 40px;
      line-height: 40px;
      text-align: center;
    }
    // 奇偶行改一个颜色
    .itemClass:nth-child(even) {
      background: #c7edcc;
    }
    .itemClass:nth-child(odd) {
      background: pink;
    }
  }
  .loadingBox {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(255, 255, 255, 0.64);
    color: green;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
</style>
复制代码

使用vxetable插件实现虚拟列表

如果不是列表,是table表格的话,笔者这里推荐一个好用的UI组件,vxetable,看名字就知道做的是表格相关的业务。其中就包括虚拟列表。

vue2vue3版本都支持,性能比较好,官方说:虚拟滚动(最大可以支撑 5w 列、30w 行)

强大!

官方网站地址:vxetable.cn/v3/#/table/…

效果图

效果很丝滑

安装使用代码

注意安装版本,笔者使用的版本如下:

cnpm i xe-utils vxe-table@3.6.11 --save

main.js

// 使用VXETable
import VXETable from 'vxe-table'
import 'vxe-table/lib/style.css'
Vue.use(VXETable)
复制代码

代码方面也很简单,如下:

<template>
  <div class="box">
    <vxe-table
      border
      show-overflow
      ref="xTable1"
      height="300"
      :row-config="{ isHover: true }"
      :loading="loading"
    >
      <vxe-column type="seq"></vxe-column>
      <vxe-column field="id" title="ID"></vxe-column>
      <vxe-column field="name" title="名字"></vxe-column>
      <vxe-column field="value" title="对应值"></vxe-column>
    </vxe-table>
  </div>
</template>

<script>
import axios from "axios";
export default {
  data() {
    return {
      loading: false,
    };
  },
  async created() {
    this.loading = true;
    const res = await axios.get("http://ashuai.work:10000/bigData");
    this.loading = false;
    this.render(res.data.data);
  },
  methods: {
    render(data) {
      this.$nextTick(() => {
        const $table = this.$refs.xTable1;
        $table.loadData(data);
      });
    },
  },
};
</script>
复制代码

方案七 开启多线程Web Worker进行操作

本案例中,使用Web Worker另外开启一个线程去操作代码逻辑,收益并不是特别大(假如使用虚拟滚动列表插件的情况下)

不过也算是一个拓展的思路吧,面试的时候,倒是可以说一说,提一提。

Web Worker不熟悉的道友们,可以看看笔者之前的这篇文章:《性能优化之使用vue-worker插件(基于Web Worker)开启多线程运算提高效率》

方案八 未雨绸缪,防患于未然

以下为笔者愚见,仅供参考...

  • 在上述解决方案都说完以后,并没有结束。
  • 实际上本题目在考查候选人知识的广度和深度以外,更是考查了候选人的处理问题的思考方式,这一点尤其重要!
  • 笔者曾做过候选人去求职,也曾做过面试官去面试。就程序员开发工作而言,技术知识点不熟悉,可以快速学习,如文档、谷歌、百度、技术交流群,相关同事都可提供一定的支持
  • 更重要的是看中候选人的思考方式,思维模式
  • 试想,两个候选人实力水平差不多,但是一个只知道埋头苦干,有活就干,不去斟酌;而另外一个却是在用心工作的时候,也会仰望星空,会分析如何干活能够高性价比地完成任务,注重过程与结果
  • 这样的话,哪个更加受欢迎一些呢?

如果笔者是候选人,笔者在说了上述7种方案以后,会再补充第八种方案:未雨绸缪,防患于未然


场景模拟

面试官随意打量着其手中我的简历,抚须怪叫一声:“小子,后端要一次性返回10万条数据给你,你如何处理?”

我眉毛一挑,歪嘴一笑:“在上述7种方案陈述完以后,我想类似的问题,我们可以从根本上去解决。即第八种方案,要未雨绸缪,防患于未然。”

“哦?”面试官心中疑惑,缓缓放下我的简历:“愿闻其详。”

我不紧不慢地答道:“在具体开发工作中,我们在接到一个需求时,在技术评审期间,我们就要和后端去商量比较合适的技术解决方案。这个问题是后端要一次性返回我10万条数据,重点并不在10万条这么多数据,而在于后端为什么要这样做?”

面试官抬头,瞳孔中倒映出我的身影,认真听了起来。

我一字一顿地说道:“除去**业务真正需要这种方案**的话(若是客户要求的,那就没啥好说的,干就完了),后端这样做的原因大致有两种,第一种他不太懂sql的limit语句,但这基本不可能,第二种就是他有事情,随便敷衍写了一下。所以,就是要和他沟通,从大数据量接口请求时长过长,以及过多的dom元素渲染导致性能变差,以及项目的可维护性等角度去沟通,我相信只要正确的沟通,就能从根源上去避免这种不太合理的情况发生。”

面试官又突然狡黠地发问:“要是沟通以后,后端死活不给你分页呢?你咋办?嗨嗨!你的沟通无效果!你如何处理!人家不听你的!”似乎是觉得这个问题很刁钻,他双臂抱在胸前,靠在椅背上,发出桀桀桀的诡异笑声,他等待着看到我脸上即将绽放的回答不上来的,尴尬笑容。

我内心冷哼一声:雕虫小技...

我盯着面试官的眼睛,认真说道:“如果工作中沟通无效果,要么是我自己沟通语言表达的问题,这一点我会注意,不断提升自己的沟通技巧和说话方式,要么就是...”

我声音扬起了三分:“我沟通的这个人有问题!他工作摸鱼偷懒耍滑!固执己见!为难他人!高高在上!自以为是!这种情况下,我会找到我的直属领导去介入,因为这已经不是项目的需求问题了,而是员工的基本素养问题!”

停顿了一秒,我声音又柔和了几分:“但是,但是我相信咱们公司员工中是绝对没有这样的人存在的,各个都是能力强悍,态度端正的优秀员工。毕竟咱们公司在行业中久负盛名,我也是因此慕名而来的。您说对吧?”

面试官眼中闪过震惊之色,他没有想到我居然把皮球又踢给他了,不过他为了维持形象,旋即恢复了镇定,只是面部肌肉在止不住的微微颤抖。

“那是当然,公司人才济济。”面试官随口接话道。

我又补充道:“实际上在工作中,前端作为比较贴近用户的角色而言,需要和各个岗位的同事进行沟通,比如后端、产品、UI、测试等。我们需要通过合理的沟通方式,去提升工作效率,完成项目,实现自己的价值,为公司创造收益,我想这是每一个员工需要做的,也是必须要做到的。”

面试官又抚须怪叫一声:“小子表现还行,你被录用了!一个月工资2200,自带电脑,无社无金,007工作制,不能偷吃公司零食,以及...”

我:阿哒...

总结

有效的沟通,源自于解决问题的思维模式,在多数情况下,重要性,大于当下所掌握的技术知识点

  • 网站效果演示地址:ashuai.work:8888/#/bigData
  • GitHub仓库地址:github.com/shuirongshu…

 

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

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

相关文章

【unity项目实战】3DRPG游戏开发06——敌人和攻击

导入敌人素材 RPG Monster Duo PBR Polyart 拖入敌人,如果觉得他的亮度有点低,选择他本体,可以选择调节修改他材质球metllic alpha的值 我们新建一个敌人脚本,我们的所有敌人都会挂载这个脚本,如果我们希望每个敌人都挂载导航组件,一个添加无疑是很麻烦的,我们可以使…

基于ESP32的zigbee温湿度采集系统

一. 系统设计及框图&#xff1a; 本设计可以实现通过ZIGBEE传输温湿度信息和开关量信号到云端然后再通过手机APP显示。系统分为发射端和接收端&#xff0c;发送端采集温湿度信息后通过ZIGBEE发送到接收端&#xff0c;接收端接收到温湿度信息后上传到云端并通过手机APP显示。 …

import _jpype ImportError: DLL load failed: 找不到指定的模块

问题记录及解决思路 &#xff08;1&#xff09;问题记录 当python3需要调用java程序的需求时&#xff0c;需要使用到jpype这个库&#xff0c;尝试通过pip install jpype 进行安装&#xff0c;结果提示没有这个库&#xff0c;看网上教程提示pip install jpype1进行安装还是有问…

游戏测试的整个流程是什么

在游戏行业中&#xff0c;游戏测试是一个非常重要的岗位&#xff0c;并且游戏测试的内容是比较复杂的&#xff0c;除了对游戏的整体流程有一定的了解之外&#xff0c;还需要对一些细节部分有所了解。那么&#xff0c;一个完整的游戏测试流程是怎么样的呢? 游戏测试其实并不是一…

扎克伯格:同时专注AI和Metaverse,Quest 3将是下一个里程碑

自更名以来&#xff0c;Meta大张旗鼓的重磅投入元宇宙面临了一系列风波&#xff0c;市场经济不景气&#xff0c;广告利润下降&#xff0c;大幅裁员、重组等。 23年1季度Meta实现营收增长&#xff0c;好于预期&#xff0c;而此前三个季度同比都是下跌&#xff0c;可见“效率年”…

【AI实战】微小目标检测模型SSPNet--训练环境从零开始搭建

【AI实战】微小目标检测模型SSPNet--训练环境从零开始搭建 SSPNet介绍环境搭建安装依赖参考 SSPNet介绍 SSPNet: Scale Selection Pyramid Network for Tiny Person Detection from UAV Images 官方连接 https://github.com/MingboHong/SSPNetarxiv https://arxiv.org/abs/210…

ValueError: Please specify `target_modules` in `peft_config`解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

hive进阶——在centos7里面配置mysql,将原来hive的客户端扩展

系列文章目录 centos集群上安装hive客户端的操作步骤以及hive介绍 文章目录 一、启动hive客户端 二、在Hive上面安装MySQL 2.1、MySQL安装 1 检查当前系统是否安装过 MySQL 2 将 MySQL安装包拷贝到 /opt/software目录下 3 解压 MySQL安装包 ​4 在安装目录下执行 rpm …

泰迪杯|第十一届“泰迪杯”挑战赛作品提交仅剩2天了!

提交作品截止时间: 2023年4月28日 16:00:00 距离第十一届“泰迪杯”数据挖掘挑战赛提交作品结束时间只剩2天了&#xff0c;相信大家都在做着最后的更改。小编为大家整理了一些提交的步骤及注意事项&#xff0c;记得一定要调好闹钟&#xff0c;不要错过提交时间哦。 01 在作…

【Cpp】前K个高频单词-排序的稳定性

文章目录 题目思路1--使用sort排序并优化其稳定性方法一:方法二 思路2--multiset 题目 https://leetcode.cn/problems/top-k-frequent-words/description/ 思路1–使用sort排序并优化其稳定性 我们可以直接先将每个单词出现的次数用一个CountMap统计出来,然后放入一个vecto…

超级详细的华为OSPF实验及配置

什么是OSPF&#xff1f; 开放式最短路径优先OSPF&#xff08;Open Shortest Path First&#xff09;是IETF组织开发的一个基于链路状态的内部网关协议&#xff08;Interior Gateway Protocol&#xff09;。 目前针对IPv4协议使用的是OSPF Version 2&#xff08;RFC2328&#x…

【Linux】8、查看 Linux 主机运行状态、压缩和解压缩命令、Linux 的环境变量

目录 一、查看 Linux 系统资源占用二、硬盘信息监控三、网络监控命令四、Linux 文件上传和下载命令五、压缩和解压(1) 压缩格式(2) tar 命令 六、Linux 的环境变量 一、查看 Linux 系统资源占用 ✒️ 可通过 top 命令查看系统的 CPU、内存的使用情况&#xff08;类似 Windows …

超详细Redis入门教程——Redis 持久化

前言 本文小新为大家带来 超详细Redis入门教程——Redis 持久化 相关知识&#xff0c;具体内容包括持久化基本原理&#xff0c;RDB 持久化&#xff08;包括&#xff1a;持久化的执行&#xff0c;RDB 优化配置&#xff0c;RDB 文件结构&#xff0c;RDB 持久化过程&#xff09;&a…

台灯护眼灯哪个牌子好用?真正适合学生使用的护眼台灯

最近家里一款陪伴了多年的灯泡的台灯因为年久失修已经损坏了&#xff0c;导致不得不换个台灯&#xff0c;而换台灯就不得不仔细挑选&#xff0c;毕竟是需要长期使用的&#xff0c;对视力方面影响还是很大的&#xff0c;通常老式台灯的光照明显对视力都产生不了太大保护&#xf…

AI可以实现陪伴需求吗

在现代社会&#xff0c;科技日新月异&#xff0c;个性化AI定制服务已经成为一种新型的科技应用&#xff0c;被越来越多的人所接受和使用。个性化AI定制是一种基于人工智能技术的个性化服务&#xff0c;它可以帮助我们更好地规划生活&#xff0c;为我们提供情感上的陪伴和生活上…

Go 1.21新特性前瞻

Go 1.21版本[1]正在如火如荼地开发当中&#xff0c;按照Go核心团队的一年两次的发布节奏来算&#xff0c;Go 1.21版本预计将在2023年8月发布(Go 1.20版本[2]是在2023年2月份发布的)。 本文将和大家一起看看Go 1.21都会带来哪些新特性。不过由于目前为时尚早&#xff0c;下面列出…

AI绘图实战(七):室内设计线稿渲染、景观设计手绘稿改动、建筑照片转线稿|Stable Diffusion成为设计师生产力工具

S&#xff1a;AI能取代设计师么&#xff1f; I &#xff1a;至少在设计行业&#xff0c;目前AI扮演的主要角色还是超级工具&#xff0c;要顶替&#xff1f;除非甲方对设计效果无所畏惧~~ 预先学习&#xff1a; 安装及其问题解决参考&#xff1a;《Windows安装Stable Diffusion …

03.DolphinScheduler资源中心

文章目录 文件管理基础操作创建文件上传文件文件查看下载文件文件重命名删除文件 任务样例创建 shell 文件创建工作流执行文件查看结果 UDF管理函数管理任务样例编写 UDF 函数配置 UDF 函数使用 UDF 函数 任务组管理任务组配置新建任务组查看任务组队列任务组的使用 任务组的实…

【刷题】Java日常刷题1

A.Sort the Subarray 题意&#xff1a;给出一个数组&#xff0c;一个在此基础上被操作过的数组&#xff0c;找出被操作过的最长的非递减连续序列。 题解&#xff1a;这道题最开始写就被给的样例迷惑了&#xff0c;给出的样例都是被操作过出现非递减序列的片段&#xff0c;因此…

No.049<软考>《(高项)备考大全》【冲刺3】《软考之 119个工具 (1)》

《软考之 119个工具 &#xff08;2&#xff09;》 1.专家判断2.引导技术:3.项目管理信息系统:4.会议:5.分析技术:6.变更控制工具:7.访谈:8.焦点小组会议:9.引导式研讨会:10.群体创新技术:11.群体决策技术:12.问卷调查:13.观察:14.原型法:15.标杆对照:16.系统交互图:17.文件分析…