1,关于阿里播放器使用过的几种播放方式

url (source)

① 要在创建播放器前要拿到资源否则会报错

② 在有不同清晰度的资源时  直接调用 player.loadByUrl() 方法会报错 官网给出的例子:JSON.stringify({ 'FD': videoUrl.Fd, 'SD': videoUrl.Sd })   (首次可以播,但在切换时资源路径会出错,官网的demo只有单个视频,无法测试切换)

解决方法是 直接抛弃 player.loadByUrl()  ,每次销毁播放器,然后重新创建。

vid+playauth:

这种方式清晰度不需要自己设置,但坑比较多。在F5刷新后视频组件会丢失,只剩下封面,并且此类型必须额外写入一些配置,指定清晰度等等。

这种方式切换视频源不用player.loadByUrl() ,要用  player.replayByVidAndPlayAuth(this.vid, this.playauth)  方法

        // vid+playauth播放
        // vid: this.vid,
        // playauth: this.playauth,
        // encryptType: '1', // 播放加密视频
        // qualitySort: "asc", // 指定排序方式,只有使用Vid + PlayAuth播放方式时支持。
        // format: "m3u8", // 指定播放地址格式,只有使用vid的播放方式时支持可选值。
        // definition: "FD,LD,SD,HD,OD,2K,4K", // 此值是vid对应流清晰度的一个子集,仅H5模式支持。
        // defaultDefinition: 'SD', // 默认视频清晰度,此值是vid对应流的一个清晰度,仅H5模式支持。

2,需注意这几种事件的坑,在记录上报,播放时常要在 播放中playing 而不是 播放play 中执行,播放完毕后顺序播放可以用自带组件,这里是自己实现,但是有个bug是 ended播放完毕回调中 事件会执行两次!这里是设置了个开关来限制的。

3,配置中有个 skinLayout 可以设置一些播放组件,其中 setting 里自带倍速,字幕,音轨,清晰度,但是字幕和音轨这里用不到,还没法去掉。但是注释了setting又会导致 倍速和清晰度不见了。

这里官方提供了 components组件

components: [
          { name: 'RateComponent', type: AliPlayerComponent.RateComponent },
          { name: 'MemoryPlayComponent', type: AliPlayerComponent.MemoryPlayComponent },
          {
            name: 'QualityComponent',
            type: AliPlayerComponent.QualityComponent
          }],
 
RateComponent 为倍速
MemoryPlayComponent 历史记录
QualityComponent 是清晰度 ,这里有个坑,就是原本项目中引入的是   https://g.alicdn.com/de/prismplayer/2.8.1/aliplayer-min.js   (2.8.1版本的js和css)导致 一引入 清晰度组件就会报错,一只到不到原因,后来修改为 2.9.23版本的,报错消失。
 
4,倍速功能,因为有之前的坑,每次会销毁播放器重新创建,所以导致播放下一个视频时倍速会重置成1,官网还没有提供切换倍速抛出的事件,所以就捕获不到倍速的改变,也就无法在下一个时去设置倍速。只能手写一个倍速盒子点击时去对接阿里的方法。
 
音乐播放器的代码:
<template>
<!-- 容器 -->
<div class="container">
<!-- 音频播放器 -->
<transition name="el-zoom-in-top">
<div v-show="isShowPlayer" class="audioWrapper">
<div class="header">
<div class="title">正在播放 {{playingAudioName}}</div>
<img class="close" src="@/assets/image/close.png" alt="关闭播放器" @click="closePlayer">
</div>
<div class="audio-box" v-loading="playerLoading">
<img :src="play?pauseIcon:playIcon" alt="播放暂停" @click="playHandle()">
<div class="audio-progress">
<el-slider v-model="sliderVal" :format-tooltip="formatTooltip" :min="sliderMin" :max="sliderMax" @change="sliderChange"></el-slider>
<div id="aliPlayer"></div>
<div class="audio-info">
<div>
<span class="current-time">{{currentTime}}</span>
<span class="time-middle">/</span>
<em class="time-long">{{duration}}</em>
</div>
<div class="util-box">
<span @click="isShowRateList = !isShowRateList">倍速{{rateVal}}x</span>
<ul v-if="isShowRateList">
<li v-for="(t,i) in playBackRateList" :key="i" @click="changeRate(t)">{{t}}</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</transition>
</div>
</template> <script>
import { courseStore } from "@/store/course.js";
import { tokenStore } from "@/store/user.js";
export default {
layout: 'detail',
name: 'CourseCatalogue', // 校验动态路由参数的有效性
validate({ params, query }) { },
// 获取详情数据
async asyncData({ $axios, params }) {
return { }
}, // 处理数据
created() { }, mounted() {
// 初始化播放器
this.createPlayer() }, // 销毁定时器及阿里播放器
beforeDestroy() {
this.stopReportLearning()
if (this.player) {
this.player.dispose()
this.player = null
}
}, //
computed: { },
data() {
return {
store: courseStore(), // 课程商店
userStore: tokenStore(), // 用户商店 seeked: true, // 是否可续播
// 播放相关
canplay: false,// 是否可以播放
isShowPlayer: false,// 是否显示播放器
playerLoading: true, // 播放器loading
playingAudioName: '', // 正在播放的课程名称
player: null, // 播放器
timer: null, // 学习上报定时器
playDate: '', // 当前视频的时间戳
opener: true,
playerUrl: '/a.m3u8', // 播放的资源路径
sliderVal: 0, // 滑块当前时长。
sliderMin: 0,
sliderMax: 0, // 滑块的总时长。
currentTime: '00:00', // 当前播放时间
duration: '00:00', // 总时长
play: false, // 播放ing?暂停?
// 播放/暂停图标
playIcon: require('@/assets/image/play.png'),
pauseIcon: require('@/assets/image/pause.png'),
isShowRateList: false, // 是否展示倍速列表
rateVal: 1, // 当前倍速
playBackRateList: [0.25, 0.5, 0.75, '正常', 1.25, 1.5, 1.75, 2], // 倍速
}
},
methods: {
// 获取vid+playauth
getVid() { },// 初始化播放器
createPlayer() {
let prop = {
id: "aliPlayer",
source: this.playerUrl,
mediaType: "audio",
width: "100%",
height: "100%",
autoplay: false, // 自动播放
isLive: false, // 直播
rePlay: false, // 循环播放
playsinline: true, //H5是否内置播放
preload: true, //播放器自动加载
language: "zh-cn", // 语言
cover: '', //播放器默认封面图片,需要autoplay为’false’时,才生效
controlBarVisibility: "hover", //控制面板的实现 ‘click’ 点击出现、‘hover’ 浮动出现、‘always’ 一直在
useH5Prism: true //指定使用H5播放器
} this.player = new Aliplayer(prop, function (player) {
console.log("The player is created");
}) // 播放 (由暂停恢复为播放时触发)
this.player.on('play', () => {
this.play = true
}) // 暂停
this.player.on('pause', () => {
this.play = false
this.stopReportLearning()
}) // 播放ing (播放中,会触发多次)
this.player.on('playing', () => {
// console.log('播放中ing') // 学习记录上报
this.learningReport()
}) // 可以播放
this.player.on('canplay', () => {
this.playerLoading = false
const courseInfo = this.store.getCourseInfo
if (this.canplay && this.seeked && courseInfo.duration && courseInfo.newestLessonId === courseInfo.lessonId) {
this.seeked = false
this.player.seek(courseInfo.duration)
}
}) // 等待缓冲
this.player.on('waiting', () => {
this.playerLoading = true
}) // 时长发生变动时
this.player.on('timeupdate', () => {
this.updateTime()
}) // 播放出错
this.player.on('error', () => {
this.$message.error('播放出错')
this.stopReportLearning()
this.sliderVal = 0
this.play = false
this.playerLoading = true
this.isShowPlayer = false
this.store.setIsPlaying(false)
}) // 播放完毕
this.player.on("ended", () => {
if (this.opener) {
this.opener = false
console.log('播放完了!') // 停止学习上报
this.stopReportLearning()
this.playDate = '' // 调用子组件方法,自动播放下一个
const courseInfo = this.store.getCourseInfo
this.$refs.CourseCurriculum.createdPlayList(courseInfo.courseId, courseInfo.lessonId)
}
});
}, // 学习记录上报
learningReport() { // 先清空
this.stopReportLearning() const courseInfo = this.store.getCourseInfo
const lessonAudioVideo = courseInfo.lessonAudioVideo // 播放时长小于1时不进行上报
// if (curTime <= 1) {
// return
// } if (this.playDate === '') {
const nowDate = new Date
this.playDate = nowDate.getTime()
} // 学次唯一值
const userInfo = this.userStore.getUserInfo
const key = `${userInfo.userId}_${courseInfo.orderId}_${courseInfo.projectId}_${courseInfo.courseId}_${courseInfo.lessonId}_${this.playDate}`;
const sessionKey = this.$md5(key) this.timer = setInterval(() => {
const curTime = parseInt(this.player.getCurrentTime())
this.$axios.$post('/hadoop/learning/learningRecordSend', {
sessionKey: sessionKey,
orderId: courseInfo.orderId,
projectId: courseInfo.projectId,
courseId: courseInfo.courseId,
courseCatalogId: courseInfo.lessonId,
resourceType: lessonAudioVideo.type,
resourceId: lessonAudioVideo.audioId,
duration: curTime
}).then(() => { }).catch((err) => {
if (err.code === 10009) this.player.pause()
});
}, 5000)
}, // 停止上报学习记录
stopReportLearning() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
}, // 关闭播放器
closePlayer() {
this.isShowPlayer = false
this.store.setIsPlaying(false)
this.stopReportLearning()
this.play = false
this.playerLoading = true
this.player.pause()
}, // 播放/暂停
playHandle() {
this.play = !this.play
this.play ? this.player.play() : this.player.pause()
}, // 更新时间
updateTime() {
if (!Number.isFinite(this.player.getDuration())) {
this.currentTime = Number.MAX_SAFE_INTEGER;
this.currentTime = '00:00';
} else {
const total = this.formatTime(this.player.getDuration())
const current = this.formatTime(this.player.getCurrentTime())
this.duration = `${total.min}:${total.sec}`
this.currentTime = `${current.min}:${current.sec}`
this.sliderVal = Math.floor(this.player.getCurrentTime())
this.sliderMax = Math.floor(this.player.getDuration())
}
}, // 格式化毫秒,返回String型分秒对象
formatTime(time) {
// 如果没获取到
if (!time) return { min: '00', sec: '00' }
return {
min: Math.floor(time / 60).toString().padStart(2, '0'),
sec: Math.floor(time % 60).toString().padStart(2, '0')
}
}, // 格式化毫秒数,对应elm滑块组件
formatTooltip(val) {
const time = this.formatTime(val)
return `${time.min}:${time.sec}`
}, // 滑块松动后触发。更新当前时长,
// 时长发生变动会init里的方法进行更新数据
sliderChange(val) {
this.player.seek(this.sliderVal)
}, // 倍速改变时
changeRate(t) {
if (t === '正常') t = 1;
this.rateVal = t
this.player.setSpeed(t)
this.isShowRateList = false
},
}
}
</script>

视频播放代码:

<template>
<div class="wrap">
<!-- 视频区域 -->
<div class="video" :class="{'w1': sideBarFlag}"> <!-- 视频 -->
<div class="player" id="aliVideoPlayer"></div> </div> <!-- 侧边栏区域 --> </div>
</template> <script>
import { courseStore } from "@/store/course.js";
import { tokenStore } from "@/store/user.js";
export default {
layout: 'index',
async asyncData({ $axios, query }) {
const [chapterList] = await Promise.all([
// 获取视频资源
// $axios.$get(`/resources/resources/video/${lessonAudioVideo.videoId}`),
// 获取课程列表
$axios.$get('/learning/user/project/pc/catalog/v1', {
params: {
projectId: query.projectId,
courseId: query.courseId
}
}),
])
return {
// videoData,
chapterList
}
},
data() {
return {
store: courseStore(), // 课程商店
userStore: tokenStore(), // 用户商店
courseInfo: {},// 当前播放的课程相关信息
player: null, // 播放器
opener: true,
playerUrl: '', // 播放的资源url
vid: '', // vid + playauth
playauth: '',
lessonName: '', // 当前播放的课次名称
seeked: true, // 是否可续播
speed: 1, // 倍速
// 侧边栏
sideBarFlag: true,
// 目录/笔记
listFlag: true,
// 学习上报定时器
timer: null,
// 当前视频的时间戳
playDate: '',
}
}, beforeMount() {
this.courseInfo = this.store.getCourseInfo
// 获取视频资源url
// this.playerUrl = this.courseInfo.lessonAudioVideo.url
}, async mounted() {
// 获取视频vid+playauth
const videoInfo = await this.getVid()
this.playerUrl = JSON.stringify({ 'FD': videoInfo.Fd, 'SD': videoInfo.Sd })
// this.vid = videoInfo.VideoId
// this.playauth = videoInfo.PlayAuth
// 初始化播放器
this.createPlayer()
}, // 销毁定时器
beforeDestroy() {
this.stopReportLearning()
if (this.player) {
this.player.dispose()
this.player = null
}
}, methods: {
// 获取vid+playauth
getVid() {
return this.$axios.$get(`/file/sys/file/getVideoPlayUrl`, {
params: {
videoId: this.courseInfo.lessonAudioVideo.resourcesId
}
})
},
// 初始化播放器
createPlayer() {
let prop = {
id: "aliVideoPlayer", // 资源url播放
source: this.playerUrl, // vid+playauth播放
// vid: this.vid,
// playauth: this.playauth,
// encryptType: '1', // 播放加密视频
// qualitySort: "asc", // 指定排序方式,只有使用Vid + PlayAuth播放方式时支持。
// format: "m3u8", // 指定播放地址格式,只有使用vid的播放方式时支持可选值。
// definition: "FD,LD,SD,HD,OD,2K,4K", // 此值是vid对应流清晰度的一个子集,仅H5模式支持。
// defaultDefinition: 'SD', // 默认视频清晰度,此值是vid对应流的一个清晰度,仅H5模式支持。 mediaType: "video",
width: "100%",
height: "100%",
autoplay: true, // 自动播放
isLive: false, // 直播
rePlay: false, // 循环播放
playsinline: true, //H5是否内置播放
preload: true, //播放器自动加载
keyShortCuts: true, // 是否启用快捷键
language: "zh-cn", // 语言
cover: '', //播放器默认封面图片,需要autoplay为’false’时,才生效
controlBarVisibility: "hover", //控制面板的实现 ‘click’ 点击出现、‘hover’ 浮动出现、‘always’ 一直在
useH5Prism: true, //指定使用H5播放器
components: [
{ name: 'RateComponent', type: AliPlayerComponent.RateComponent },
{ name: 'MemoryPlayComponent', type: AliPlayerComponent.MemoryPlayComponent },
{
name: 'QualityComponent',
type: AliPlayerComponent.QualityComponent
}],
skinLayout: [
{ name: "bigPlayButton", align: "blabs", x: 30, y: 80 },
{ name: "H5Loading", align: "cc" },
{ name: "errorDisplay", align: "tlabs", x: 0, y: 0 },
{ name: "infoDisplay" },
{ name: "tooltip", align: "blabs", x: 0, y: 56 },
{ name: "thumbnail" },
{
name: "controlBar", align: "blabs", x: 0, y: 0,
children: [
{ name: "progress", align: "blabs", x: 0, y: 44 },
{ name: "playButton", align: "tl", x: 15, y: 12 },
{ name: "timeDisplay", align: "tl", x: 10, y: 7 },
{ name: "fullScreenButton", align: "tr", x: 10, y: 12 },
// { name: "subtitle", align: "tr", x: 15, y: 12 },
// { name: "setting", align: "tr", x: 15, y: 12 },
{ name: "volume", align: "tr", x: 5, y: 10 }
]
}
]
} this.player = new Aliplayer(prop, function (player) {
console.log("The player is created");
player.on('sourceloaded', function (params) {
var paramData = params.paramData
var desc = paramData.desc
var definition = paramData.definition
// 获取清晰度组件并调用清晰度组件的 setCurrentQuality 设置清晰度
player.getComponent('QualityComponent').setCurrentQuality(desc, definition)
}) // 是否有设置过倍速
if (this.speed) {
player.setSpeed(this.speed)
}
}) // 播放
this.player.on('play', () => {
// console.log('开始播放')
}) // 播放ing
this.player.on('playing', () => {
// console.log('播放中ing') this.speed = this.player.tag.playbackRate // 学习记录上报
this.learningReport()
}) // 可以播放
this.player.on('canplay', () => {
if (this.seeked && this.courseInfo.duration && this.courseInfo.newestLessonId === this.courseInfo.lessonId) {
this.seeked = false
this.player.seek(this.courseInfo.duration)
}
}) // 暂停
this.player.on('pause', () => {
// console.log('播放暂停') // 停止上报
this.stopReportLearning()
}) // 播放出错
this.player.on('error', () => {
this.$message.error('播放出错')
}) // 播放完毕
this.player.on("ended", (e) => {
if (this.opener) {
this.opener = false
console.log('播放完了!!!!!')
this.stopReportLearning()
this.playDate = '' // 调用子组件方法,自动播放下一个
this.$refs.videoList.createdPlayList(this.courseInfo.lessonId)
}
})
}, // 接受到子组件课次变化,播放新的视频
async lessonChange(doing) { this.courseInfo = this.store.getCourseInfo // 未告知要播放时,只展示课次名字
if (doing !== 'play') {
this.lessonName = this.courseInfo.lessonName
return
} // 检测播放源是否相同(目前不进行检测,否则导致点击相同资源时->无法重播)
// if (this.playerUrl !== this.courseInfo.lessonAudioVideo.url) { // 更改视频源 // TODO: url
// this.playerUrl = this.courseInfo.lessonAudioVideo.url
// this.player.loadByUrl(this.playerUrl) // TODO: vod
const videoUrl = await this.getVid()
// this.playerUrl = videoInfo.Sd
// this.player.loadByUrl(this.playerUrl)
this.player.dispose()
this.playerUrl = JSON.stringify({ 'FD': videoUrl.Fd, 'SD': videoUrl.Sd })
this.createPlayer() // TODO: vid+playauth
// this.vid = videoInfo.VideoId
// this.playauth = videoInfo.PlayAuth
// this.player.replayByVidAndPlayAuth(this.vid, this.playauth) // } else {
// this.player.play()
// } this.lessonName = this.courseInfo.lessonName
this.seeked = true
this.opener = true
}, // 停止上报学习记录,清楚定时器
stopReportLearning() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
}, // 学习记录上报
learningReport() {
// 先清空
this.stopReportLearning() const courseInfo = this.courseInfo
const lessonAudioVideo = this.courseInfo.lessonAudioVideo if (this.playDate === '') {
const nowDate = new Date
this.playDate = nowDate.getTime()
// console.log(this.playDate)
} // 学次唯一值
const userInfo = this.userStore.getUserInfo
const key = `${userInfo.userId}_${courseInfo.orderId}_${courseInfo.projectId}_${courseInfo.courseId}_${courseInfo.lessonId}_${this.playDate}`;
const sessionKey = this.$md5(key) this.timer = setInterval(() => {
const curTime = parseInt(this.player.getCurrentTime())
this.$axios.$post('/hadoop/learning/learningRecordSend', {
sessionKey: sessionKey,
orderId: courseInfo.orderId,
projectId: courseInfo.projectId,
courseId: courseInfo.courseId,
courseCatalogId: courseInfo.lessonId,
resourceType: lessonAudioVideo.type,
resourceId: lessonAudioVideo.videoId,
duration: curTime
}).then(() => { }).catch((err) => {
if (err.code === 10009) this.player.pause()
});
}, 5000)
}
}
}
</script>
 

阿里播放器Aliplayer遇到的所有坑的更多相关文章

  1. 阿里播放器踩坑记录 进度条重构 video loadByUrl失效解决方案

    如果本文对你有用,请爱心点个赞,提高排名,帮助更多的人.谢谢大家!❤ 如果解决不了,可以在文末进群交流. 文档地址:https://player.alicdn.com/aliplayer/index. ...

  2. vue+element-ui中引入阿里播放器

    1.在public文件下的index.html文件中插入以下代码: <link rel="stylesheet" href="https://g.alicdn.co ...

  3. 阿里云web播放器

    原文地址:https://help.aliyun.com/document_detail/51991.html?spm=5176.doc61109.6.703.ZTCYoi 一.概念说明 1. pla ...

  4. 如何利用阿里视频云开源组件,快速自定义你的H5播放器?

    摘要: Aliplayer希望提供一种方便.简单.灵活的机制,让客户能够扩展播放器的功能,并且Aliplayer提供一些组件的基本实现,用户可以基于这些开源的组件实现个性化功能,比如自定义UI和自己A ...

  5. 阿里云Prismplayer-Web播放器的使用

    Prismplayer是一套在线视频播放技术方案,同时支持Flash和Html5两种播放技术,可对播放器进行功能配置和皮肤定制.其在线使用文档地址为:https://help.aliyun.com/d ...

  6. 前端视频插件Aliplayer播放器简单使用(基于地址播放)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  7. RTSP播放器开发填坑之道

    好多开发者提到,在目前开源播放器如此泛滥的情况下,为什么还需要做自研框架的RTSP播放器,自研和开源播放器,到底好在哪些方面?以下大概聊聊我们的一点经验,感兴趣的,可以关注 github: 1. 低延 ...

  8. RTMP播放器开发填坑之道

    好多开发者提到,在目前开源播放器如此泛滥的情况下,为什么还需要做自研框架的RTMP播放器,自研和开源播放器,到底好在哪些方面?以下大概聊聊我们的一点经验,感兴趣的,可以关注 github: 1. 低延 ...

  9. Web播放器

    web视频播放器的使用及遇到的问题记录 TcPlayer播放器(腾讯Web超级播放器) https://cloud.tencent.com/document/product/881/20207 Ste ...

  10. iOS多播放器封装

    今年在做直播业务的时候遇到一些问题,就是在一个套播放器UI中需要多种不同的播放器(AVPlayer.IJKPlayer.AliPlayer)支持,根据ABTest开关来切换具体使用哪种播放器,并且还要 ...

随机推荐

  1. [Untiy]贪吃蛇大作战(二)——规则界面

    游戏规则界面: 从界面上可以看出,一共有三个按钮,两个切换按钮和一个退出按钮. 一共三张规则图片Sprite,我们通过设置其是否为Active来控制显示,其控制脚本代码如下: using System ...

  2. Java学习笔记:2022年1月8日

    Java学习笔记:2022年1月8日 摘要:这天主要学习了HTML超文本标记语言以及CSS层叠样式表的基本知识,主要就是通过这两种技术进行基本的网页渲染. 目录 Java学习笔记:2022年1月8日 ...

  3. .NetCore下基于FreeRedis实现的Redis6.0客户端缓存之缓存键条件优雅过滤

    前言 众所周知内存缓存(MemoryCache)数据是从内存中获取,性能表现上是最优的,但是内存缓存有一个缺点就是不支持分布式,数据在各个部署节点上各存一份,每份缓存的过期时间不一致,会导致幻读等各种 ...

  4. 使用“宝塔一键迁移”工具,将typecho博客迁移到京东云cvm云主机

    作者:京东科技 林中 服务器更换.网站搬家,对于很多开发者新手来说不是一件容易的事情,需要迁移网站程序.数据库,修改数据库连接文件等.在云迁移方案中,宝塔是非常简单好用的服务器运维面板,能够极大提升运 ...

  5. 二十三、图的遍历(BFS和DFS)

    一.概念   图的遍历(Traversing Graph)从某一顶点出发,访问图中所有顶点,且使每一顶点仅被访问一次.与树的遍历不同的是,图的遍历需要处理两种特殊情况:一是从某一顶点出发进行遍历时,可 ...

  6. 使用SQL获取当前周别,oracle日期处理

    使用SQL获取当前周别 select to_char(sysdate,'yyyyww') from dual  select to_char(to_date('20200611','yyyymmdd' ...

  7. java入门与进阶P-5.5+P-5.6

    投票统计 写一个程序,输入数量不确定的[0,9]范围内的整数,统计每一中数字出现的次数,输入-1表示结束 循环遍历 通常都是使用for循环,让循环变量i从0到<数组的length,这样循环体内最 ...

  8. Node.js学习笔记----day03

    认真学习,认真记录,每天都要有进步呀!!! 加油叭!!! 一.Node中的模块系统 使用Node编写应用程序主要就是在使用 EcmaScript 和浏览器不一样的是,在Node中没有BOM.DOM 核 ...

  9. 06yarn简介

    YARN简介 一.YARN是什么 YARN不是facebook的那个yarn,它从Hadoop 2引入,最初目的是改善MapReduce的实现,但是因为具备足够通用性,同样也可以支持其他的分布式计算模 ...

  10. 为什么 Linux 需要虚拟内存(转载)

    为什么 Linux 需要虚拟内存 原文链接: https://draveness.me/whys-the-design-os-virtual-memory/ 操作系统中的 CPU 和主内存(Main ...