游戏引擎详解——图片
图片
图片的格式
图片文件格式 |
---|
png |
jpg |
纹理压缩格式 |
---|
ETC1/2 |
PVRTC |
ASTC |
图片的属性
图片属性 | 解释 |
---|---|
分辨率 | 宽高像素值(pt),如:1024*1024 |
位深度 | 用来存储像素颜色的值,如RGBA8888,红黄蓝透明度4个维度每个8bit,一共就是32位,一般使用的就是32位,也被称为真彩色 |
文件大小 | 文件所占用的存储大小 |
图片的优化
图片的优化分为两种:
-
- 文件大小优化:这种优化会影响到包大小,较小的图片大小对于手机存储容量和网络传输速度和时间会更友好。
一般的优化方式是使用压缩工具如pngquant、tinypng等,直接压缩文件大小。
-
- 图片纹理优化:
图片文件大小压缩,不意味着读到内存中的大小会减少。
一般情况下,以ARPG8888来说,计算一个1024*1024分辨率的图片读到内存中的大小,计算公式为:
1024 * 1024 * 4 * 8 = 33,554,432 bit = 4,194,304 byte ≈ 4 mb
理解起来就是 1024 * 1024
个像素,每个像素有 argb 4
个通道,每个通道含有 8 bit
数据用来存储颜色值。
png格式不能直接被GPU识别,需要在cpu把图片读进内存中解码后,再传递给gpu使用,这样做会造成一定的cpu消耗和很大的瞬时运行内存(RAM)占用。
因为大部分gpu对于压缩后的纹理有比较好的支持,无需cpu解码,占用内存小。于是我们要寻找一种合适的纹理压缩方式。
- etc1不支持透明通道。
- etc2效果很差,容易出现色块。
- PVRTC仅能在ios上使用.
这时候astc格式就展露在我们眼前,IOS和安卓端都对astc有较好的支持率。
- iPhone6及iPad mini 4以上iOS设备支持。
- 大多数支持OpenGL ES 3.1或Vulkan的现代Android GPU也支持ASTC格式,其中包括:自Adreno 4xx / Snapdragon 415(2015年)起的高通GPU,自Mali T624(2012年)起的ARM GPU,自Tegra K1(2014年)起的NVIDIA GPU,以及自GX6250(2014年)起的PowerVR GPU。
在运行内存中来说,astc的内存使用能节省75%左右,提升巨大。
cocoscreator中源码理解
creator引擎在编译时会把选中的纹理压缩类型记录到import文件夹下的json文件中,多种图片格式以下划线‘_’区分开,下图演示里选择了astc6x6格式和webp格式,所以生成的类型就是
代码中在读取文件格式时,会根据列举的文件类型判断当前机器是否支持。由下面代码图里能够看到,7@34这里的7代表的就是第7个.astc,4代表的就是第4个.webp。若当前设备不支持astc就会去寻找webp格式。
cocoscreator中源码整个下载流程的理解(建议配合cocos2.4.11源码享用)
-
一切的一切都要从bundle.js这个类说起,类中的load函数会调用cc.assetManager.loadAny函数来下载相关资源并获取资源数据返回。
,传递的参数是资源名paths,类型type,进度回调函数onProgress,完成回调函数onComplete。
-
cc.assetManager是CCAssetManager类,这个类里有一个loadAny函数,此函数简单封装了一个Task并把task传递到pipeline中。这里的pipeline是定义在shared.js中的new Pipeline(‘normal load’, [])一个名字叫做normal load的管线,异步执行任务,管线填充在CCAssetManager类中pipeline.append(preprocess).append(load);包含一个preprocess和load方法。
task的状态为:
{input: 资源名,onProgress: onProgress,onComplete: onComplete,options: {preset: 'default',__requestType__: 'path',type: type,bundle: bundle名,__outputAsArray__: false,}
}
4. normal load–pipeline先调用preprocess,这个函数里对Task的options属性做遍历,这里也就是preset、requestType、type、bundle和__outputAsArray__五个key。
requestType、type、bundle和preset键值对保存到subOptions对象中,__outputAsArray__和preset保存到leftOptions对象中,并覆盖掉task的options属性。
新建一个subTask,input为task.input,options为subOptions对象,走transformPipeline管线流程同步执行任务,获取的值设置为task.source和task.output。最后调用done()。
task的状态为:
{input: 资源名,onProgress: onProgress,onComplete: onComplete,options: {preset: 'default',__outputAsArray__: false,},output: ,source: ,
}
subTask的状态为:
{input: 资源名,options: {preset: 'default',__requestType__: 'path',type: type,bundle: bundle名,}
}
5. transformPipeline里包含两个函数parse和combine。
- parse管线任务,先判断input,若input为字符串,新建一个无原型链对象item,把item对象的【options.__requestType__值】,也就是【RequestType.PATH】,也就是【‘path’】设置为input值,把options中的其他键值对都复制到item中,这里包含四个键值对,requestType、type、bundle和path。
再遍历item,这里只有path这个key有处理,其他key都过滤了,通过bundle的_config找item.path值的info。这里的item.path也就是我们一开始传进来的资源名。info里包含了资源的uuid。
把config、info和uuid值填入到out对象中,并把out对象push到task.output中。
管线会把task.output值赋值给task.input。
subTask的状态为:
{options: {preset: 'default',__requestType__: 'path',type: type,bundle: bundle名,},input: [{config: bundle所有配置,uuid: 资源的uuid,info: {path: path, uuid: uuid},ext: '.json',}]
}
源码展示:
function parse (task) {var input = task.input, options = task.options;input = Array.isArray(input) ? input : [ input ];task.output = [];for (var i = 0; i < input.length; i ++ ) {var item = input[i];var out = RequestItem.create();if (typeof item === 'string') {item = Object.create(null);item[options.__requestType__ || RequestType.UUID] = input[i];}if (typeof item === 'object') {// local options will overlap glabal optionscc.js.addon(item, options);if (item.preset) {cc.js.addon(item, cc.assetManager.presets[item.preset]);}for (var key in item) {switch (key) {case RequestType.UUID: var uuid = out.uuid = decodeUuid(item.uuid);if (bundles.has(item.bundle)) {var config = bundles.get(item.bundle)._config;var info = config.getAssetInfo(uuid);if (info && info.redirect) {if (!bundles.has(info.redirect)) throw new Error(`Please load bundle ${info.redirect} first`);config = bundles.get(info.redirect)._config;info = config.getAssetInfo(uuid);}out.config = config;out.info = info;}out.ext = item.ext || '.json';break;case '__requestType__':case 'ext': case 'bundle':case 'preset':case 'type': break;case RequestType.DIR: if (bundles.has(item.bundle)) {var infos = [];bundles.get(item.bundle)._config.getDirWithPath(item.dir, item.type, infos);for (let i = 0, l = infos.length; i < l; i++) {var info = infos[i];input.push({uuid: info.uuid, __isNative__: false, ext: '.json', bundle: item.bundle});}}out.recycle();out = null;break;case RequestType.PATH: if (bundles.has(item.bundle)) {var config = bundles.get(item.bundle)._config;var info = config.getInfoWithPath(item.path, item.type);if (info && info.redirect) {if (!bundles.has(info.redirect)) throw new Error(`you need to load bundle ${info.redirect} first`);config = bundles.get(info.redirect)._config;info = config.getAssetInfo(info.uuid);}if (!info) {out.recycle();throw new Error(`Bundle ${item.bundle} doesn't contain ${item.path}`);}out.config = config; out.uuid = info.uuid;out.info = info;}out.ext = item.ext || '.json';break;case RequestType.SCENE:if (bundles.has(item.bundle)) {var config = bundles.get(item.bundle)._config;var info = config.getSceneInfo(item.scene);if (info && info.redirect) {if (!bundles.has(info.redirect)) throw new Error(`you need to load bundle ${info.redirect} first`);config = bundles.get(info.redirect)._config;info = config.getAssetInfo(info.uuid);}if (!info) {out.recycle();throw new Error(`Bundle ${config.name} doesn't contain scene ${item.scene}`);}out.config = config; out.uuid = info.uuid;out.info = info;}break;case '__isNative__': out.isNative = item.__isNative__;break;case RequestType.URL: out.url = item.url;out.uuid = item.uuid || item.url;out.ext = item.ext || cc.path.extname(item.url);out.isNative = item.__isNative__ !== undefined ? item.__isNative__ : true;break;default: out.options[key] = item[key];}if (!out) break;}}if (!out) continue;task.output.push(out);if (!out.uuid && !out.url) throw new Error('Can not parse this input:' + JSON.stringify(item));}return null;
}
- combine管线任务,主要是拼出来完整的资源地址。
subTask的状态为:
{options: {preset: 'default',__requestType__: 'path',type: type,bundle: bundle名,},output: [{config: bundle所有配置,uuid: 资源的uuid,info: {path: path, uuid: uuid},ext: '.json',url: 具体地址,}]
}
task的状态为:
{input: 资源名,onProgress: onProgress,onComplete: onComplete,options: {preset: 'default',__outputAsArray__: false,},output: [{config: bundle所有配置,uuid: 资源的uuid,info: 具体信息,ext: '.json',url: 具体地址,}],source: [{config: bundle所有配置,uuid: 资源的uuid,info: 具体信息,ext: '.json',url: 具体地址,}],
}
源码展示:
function combine (task) {var input = task.output = task.input;for (var i = 0; i < input.length; i++) {var item = input[i];if (item.url) continue;var url = '', base = '';var config = item.config;if (item.isNative) {base = (config && config.nativeBase) ? (config.base + config.nativeBase) : cc.assetManager.generalNativeBase;} else {base = (config && config.importBase) ? (config.base + config.importBase) : cc.assetManager.generalImportBase;}let uuid = item.uuid;var ver = '';if (item.info) {if (item.isNative) {ver = item.info.nativeVer ? ('.' + item.info.nativeVer) : '';}else {ver = item.info.ver ? ('.' + item.info.ver) : '';}}// ugly hack, WeChat does not support loading font likes 'myfont.dw213.ttf'. So append hash to directoryif (item.ext === '.ttf') {url = `${base}/${uuid.slice(0, 2)}/${uuid}${ver}/${item.options.__nativeName__}`;}else {url = `${base}/${uuid.slice(0, 2)}/${uuid}${ver}${item.ext}`;}item.url = url;}return null;
}
- 管线运行完毕,返回subTask.output
- 回到normal load管线任务中的preprocess任务,transformPipeline返回了对象设置成task的output和source值。把output的值赋值给input,再把output设为null,继续下一个normal load管线任务load。
task的状态为:
{onProgress: onProgress,onComplete: onComplete,options: {preset: 'default',__outputAsArray__: false,},input: [{config: bundle所有配置,uuid: 资源的uuid,info: {path: path, uuid: uuid},ext: '.json',url: 具体地址,}],source: [{config: bundle所有配置,uuid: 资源的uuid,info: 具体信息,ext: '.json',url: 具体地址,}],
}
- load函数里给task.options新增了progress和__exclude__字段,progress用来记录资源下载进度。然后遍历每一个task.input,对每一个需要load的资源新建了一个subTask,input值为每一个task的input值,onProgress为task.onProgress,options为task.options,progress为task.progress,onComplete为新的函数,完成时调用,更新progress中的值。再把这个subTask传递到loadOneAssetPipeline下载管道中。
subTask的状态为:
{input: {config: bundle所有配置,uuid: 资源的uuid,info: {path: path, uuid: uuid},ext: '.json',url: 具体地址,},onProgress: onProgress,onComplete: newComplete,options: {preset: 'default',__outputAsArray__: false,__exclude__: {},},
}
task的状态为:
{onProgress: onProgress,onComplete: onComplete,progress : { finish: 0, total: task.input.length, canInvoke: true },options: {preset: 'default',__outputAsArray__: false,__exclude__: {},},input: [{config: bundle所有配置,uuid: 资源的uuid,info: 具体信息,ext: '.json',url: 具体地址,}],source: [{config: bundle所有配置,uuid: 资源的uuid,info: 具体信息,ext: '.json',url: 具体地址,}],
}
源码展示:
function load (task, done) {let firstTask = false;if (!task.progress) {task.progress = { finish: 0, total: task.input.length, canInvoke: true };firstTask = true;}var options = task.options, progress = task.progress;options.__exclude__ = options.__exclude__ || Object.create(null);task.output = [];forEach(task.input, function (item, cb) {let subTask = Task.create({ input: item, onProgress: task.onProgress, options, progress, onComplete: function (err, item) {if (err && !task.isFinish) {if (!cc.assetManager.force || firstTask) {if (!CC_EDITOR) {cc.error(err.message, err.stack);}progress.canInvoke = false;done(err);}else {progress.canInvoke && task.dispatch('progress', ++progress.finish, progress.total, item);}}task.output.push(item);subTask.recycle();cb();}});loadOneAssetPipeline.async(subTask);}, function () {options.__exclude__ = null;if (task.isFinish) {clear(task, true);return task.dispatch('error');}gatherAsset(task);clear(task, true);done();});
}
- loadOneAssetPipeline下载单资源管线包含两个管线任务,fetch和parse。
- fetch函数调用packManager.load获取资源数据。packManager.load先判断是否在files缓存中有无此id。由于我们在加载资源前必定已经加载了fgui的bin文件,而我们都是选择合并json类型,而bin文件下载时已经把依赖的json文件下载过了,文件值都缓存到files中,这里就直接拿到json信息了,返回值赋值给task的file变量,也就是包含资源类型的json串。进入下一个管线任务parse。parse函数中对未缓存的uuid资源调用parser.parse函数,传递file值。其中又调用parser.parseImport函数,传递file和options;继续调用deserialize函数,传递file和options;继续调用cc.deserialize也就是deserialize-compiled文件中的deserialize函数,传递file和options;继续调用parseInstances;继续调用deserializeCustomCCObject;继续调用对象的_deserialize函数;这里图片对象调用的就是CCTexture2D的_deserialize函数;继续调用Texture2D._parseExt函数;这个_parseExt函数里就做了判断,对资源类型进行解析,并判断设备是否支持纹理类型,支持就返回该后缀。假设这里返回.png后缀,设置Texture2D的_native属性为.png,再设置其他属性,如过滤方案,并返回一个CCTexture2D对象。
- 这里会衍生到图片的其他属性值,原串是这样的,eg: “0,9729,9729,33071,33071,0,0,1”
- 第一个0:表示图片的纹理类型,0就是第0个.png。其他类型如下[‘.png’, ‘.jpg’, ‘.jpeg’, ‘.bmp’, ‘.webp’, ‘.pvr’, ‘.pkm’, ‘.astc’],
- 第二个9729:表示纹理缩小时设定的纹理过滤方案。const GL_NEAREST = 9728;const GL_LINEAR = 9729; 9728是最近点过滤,采样时选择最近的点,成本小,但易产生锯齿。9729是线性过滤,由4个颜色进行加权,这种方法可以让纹理边缘看起来更平滑,但需要进行更多的计算。
- 第三个9729:表示纹理放大时设定的纹理过滤方案。同上。
- 第四个33071:表示横轴纹理环绕方式。指定了当纹理坐标超出0到1的标准范围时该如何处理纹理的采样。10497是重复、33071是边缘拉伸、33648是镜像重复。
- 第五个33071:表示纵轴纹理环绕方式。同上。
- 第六个0:表示颜色是否预乘,1表示预乘,0表示非预乘。
- 第七个0:表示是否是否mipmaps。1表示使用,0表示不使用。
- 第八个1:表示纹理是否参与合图。1表示参与,0表示不参与。
- parser.parse完成后调用loadDepends函数,先为Texture2D添加addRef,然后调用getDepends函数,获取依赖,再新建一个任务,走下载管线完成实际图片加载。
相关文章:
游戏引擎详解——图片
图片 图片的格式 图片文件格式pngjpg 纹理压缩格式ETC1/2PVRTCASTC 图片的属性 图片属性解释分辨率宽高像素值(pt),如:1024*1024位深度用来存储像素颜色的值,如RGBA8888,红黄蓝透明度4个维度每个8bit&…...
电商API数据接口在电商运营电商数据分析中的作用?
电商运营中,品牌方使用电商API数据接口可以带来众多益处,具体包括但不限于以下几点: 实时数据同步:通过API接口,品牌方可以实时获取商品库存、订单状态、价格变动等信息,保证数据的时效性和准确性ÿ…...
Java OkHttp使用(二)
文章目录 引言使用 OkHttp 发送回调其他 引言 记录一下 OkHttp 的使用;OkHttp 异步发送回调请求,增加回调失败重试。 使用 OkHttp 发送回调 /*** 回调重试类*/ Data public class CallBackRetryData {/*** 回调信息JSON*/private JSONObject bodyRequ…...
宝塔(bt.cn)面板新手小白使用中常见问题
1.新手小白-服务器正确的安装宝塔的粗略教程 购买服务器后首先是挂载磁盘再安装宝塔,步骤不要搞错,免得安全后磁盘空间不对需要挂载多免费异步,切记切记 挂载磁盘:(挂载磁盘只需一行命令即可,请根据自己的系统选择正确…...
【LeetCode:3133】数组最后一个元素的最小值(Java)
题目链接 3133. 数组最后一个元素的最小值 题目描述 给你两个整数 n 和 x 。你需要构造一个长度为 n 的 正整数 数组 nums ,对于所有 0 < i < n - 1 ,满足 nums[i 1] 大于 nums[i] ,并且数组 nums 中所有元素的按位 AND 运算结果为…...
FCARM - Output Name not specified, please check ‘Options for Target - Utilities‘解决方法
出现这个问题的原因是导入文件时默认类型选错了,修改文件类型即可 如图右键导入文件,选择“Options for File OLED.C” 选择“File Type”,将头文件文件类型修改为“Text Documents file”,将.c文件文件类型修改为“C Sorce file” 第二方…...
自行车制造5G智能工厂工业物联数字孪生平台,推进制造业数字化
在当今这个日新月异的数字化时代,制造业正经历着前所未有的变革,自行车制造5G智能工厂工业物联数字孪生平台的兴起,无疑是这场转型浪潮中一股强劲力量。自行车制造5G智能工厂工业物联数字孪生平台的成功应用,不仅仅是技术上的突破…...
一文彻底搞懂Transformer - FFNN(前馈神经网络)
Transformer 神经网络: 神经网络(Neural Networks)是一种模仿生物神经网络的结构和功能的数学或计算模型。它由大量的人工神经元(也称为节点或处理单元)相互连接而成,这些神经元之间通过带有权重的连接进行…...
SpringCloud Gateway及 Springboot 服务 跨域配置
SpringCloud Gateway 跨域配置 配置文件 #跨域支持 spring.cloud.gateway.globalcors.cors-configurations.[/**].allowed-headers[0]* spring.cloud.gateway.globalcors.cors-configurations.[/**].allowed-methods[0]* spring.cloud.gateway.globalcors.cors-configuration…...
【Solidity】安全与校验
信息传输 发送方 A: 计算消息 message 的哈希值 H:hash(message) H 私钥 privateKey ➕ 哈希值 H 🟰 签名 signature:signature sign(H, privateKey) 将消息 message 和签名 signature 发送给 B 接收方 B: 计算…...
黑神话悟空四十二项修改器 v1.0
软件简介 黑神话悟空四十二项修改器由风灵月影精心打磨,为《黑神话悟空》这款备受瞩目的游戏量身定制。这款修改器界面简洁、体积小巧、功能强大,它致力于为玩家提供便捷的游戏体验,让您能够根据个人喜好和需求,轻松调整游戏内的…...
RM电控RTOS
OS即(operating system)操作系统,比如我们常用的windows系统,mac系统,android系统,ios系统,linux系统等,都属于操作系统。操作系统的本质是一个特殊的软件,它直接管理硬件…...
Arduino开源四足蜘蛛机器人制作教程
视频教程:手把手叫你做四足蜘蛛机器人——1零件介绍_哔哩哔哩_bilibili 一、项目介绍 1.1 项目介绍 Arduino主控,图形化编程,趣味学习 Arduino nano开发板舵机扩展底板 4.8V可充电电池,支持Arduino C语言编程和米思齐图形化编程…...
【Axure高保真原型】中继器表格——标签使用情况案例
今天和大家分享中继器表格——标签使用情况案例的原型模板,效果包括: 模糊搜索——输入标签编号或者标签名称,可以快速查找对应的数据 排序——点击排序按钮,可以按升序或降序排列 分页——点击上拉列表,可以选择表格…...
ABAP字符串反转 and 寻找字符所在位置 and 根据数量汇总时把数量转为非数值类型
1.字符串反转 and 寻找字符所在位置 LOOP AT gt_wlmc ASSIGNING FIELD-SYMBOL(<fs_wlmc>). "遍历内表<fs_wlmc>-matnr <fs_wlmc>-matnr(8).DATA: l_output TYPE char50,v_off2 TYPE i,str TYPE i,str2 TYPE i.CALL FUNCTION STRING_REVERS…...
【机器学习第十二章——计算学习理论】
机器学习第十二章——计算学习理论 12.计算学习理论12.1 基础知识12.1 可能学习近似正确假设(PAC)12.3 有限假设空间12.4 VC维 12.计算学习理论 12.1 基础知识 从理论上刻画了若干类型的机器学习问题中的困难和若干类型的机器学习算法的能力 这个理论要…...
Docker私人学习笔记
俗话说“好记性不如烂笔头”,编程的海洋如此的浩大,养成做笔记的习惯是成功的一步! 此笔记主要是antlr4.13版本的笔记,并且笔记都是博主自己一字一字编写和记录,有错误的地方欢迎大家指正。 一、基础概念:…...
谷粒商城实战笔记-233~235-商城业务-认证服务-单点登录流程-原理
文章目录 一,场景二,单点登录流程 一,场景 包含以下三节的内容: 一,233-商城业务-认证服务-单点登录流程-1二,233-商城业务-认证服务-单点登录流程-2三,233-商城业务-认证服务-单点登录流程-3…...
机器学习在旅游业的革新之旅
机器学习在旅游业的革新之旅 随着科技的飞速发展,尤其是人工智能(AI)技术的广泛应用,各个行业都迎来了前所未有的变革。其中,旅游业作为全球经济的重要支柱之一,更是受益匪浅。机器学习(Machin…...
OpenCTI:开源网络威胁情报平台
OpenCTI 是一个开源平台,旨在帮助组织管理其网络威胁情报 (CTI) 数据和可观察数据。 该平台由 Filigran 开发,使用基于 STIX2 标准的知识模式构建数据。 它采用现代 Web 应用程序架构,配备 GraphQL API 和用户友好的前端。 OpenCTI 与 MIS…...
linux shell 脚本 let 数学计算
linux shell 脚本 let 数学计算 http://www.codebaoku.com/it-shell/ let命令中的算术表达式必须用双引号括起来,以避免解释器对特殊字符进行处理。 在变量的计算中,不需要使用$符号来表示变量, #!/bin/shweek_daydate %u echo $week_day…...
mp3和mp4的区别是什么?怎么把mp3转成mp4?(全)
在生活中我们或多或少会听到“mp3”和“mp4”,那么什么是mp3和mp4呢?mp3和mp4的区别是什么?mp3是一种音频压缩技术,旨在在不显著牺牲音质的前提下减小音频文件的体积,使其适用于音乐和其他音频内容的存储与传输。相比之…...
合并params和query参数
场景:三级分类只有query参数,搜索框使用params参数。为了解决这个问题,文中在typeNav的index.vue和Head/index.vue分别进行了判断和处理,确保在不同的路径下合并params和query参数能正确合并并传递。 如何当点击联动框时跳转到se…...
[数据集][目标检测]工程机械车辆检测数据集VOC+YOLO格式3189张10类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):3189 标注数量(xml文件个数):3189 标注数量(txt文件个数):3189 标注…...
构建域名服务器-BIND:Linux端的安装过程及配置文件详解
文章目录 构建域名服务器工具-BINDBIND的安装BIND配置文件详解1. /etc/named.conf:2. /etc/named.rfc1912.zones:3. /var/named/named.localhost:4./etc/logrotate.d/named5./etc/named.iscdlv.key6./etc/named.root.key7./etc/rndc.conf8./e…...
linux查询目录文件基础操作
基础命令 展示所有目录 ls 长格式列出(显示文件权限、所有者、大小和最后修改时间): ls -l 忽略大小写查询 ls | grep -i name 查找特定名称的文件: find /path/to/search -name "filename" 忽略大小写查找文件&#…...
搭建TestBench,收藏这几条基本框架就够了
Verilog功能模块HDL设计完成后,并不代表设计工作的结束,还需要对设计进行进一步的仿真验证。掌握验证的方法,即如何调试自己的程序非常重要。在RTL逻辑设计中,要学会根据硬件逻辑来写测试程序即写Testbench。Verilog测试平台是一个…...
怎么利用住宅代理提高数据抓取效率
在大数据时代,数据抓取已经是从互联网收集数据的关键手段,得到了广泛的应用。不论是网络营销、电商平台、或者是新闻网站,数据抓取都可以帮助企业或者是个人收集到大量的数据。但是随着反爬虫技术的不断发展,传统的爬虫方法已经不…...
c#中的ManuaResetEvent
在C#中,ManualResetEvent 是一个同步事件,用于线程间通信。它允许一个或多个等待的线程等待某个事件的发生。当事件被设置为已发生(或称为“信号”)状态时,所有等待的线程都会被释放,并且可以继续执行。 以…...
EE trade:黄金投资的利弊与要点
黄金投资作为一种相对传统的投资途径,存在着特定的优势与风险。接下来详细剖析一下黄金投资的优缺点。 1、黄金投资的优点 有效对抗通货膨胀 在通货膨胀时期,黄金往往能有出色的表现,其价值通常会上升,如此一来便能够为投资者提…...
网站建设电话话术/惠州seo关键词排名
UVA_10806这个题目我们可以把边的容量设为1,费用设为权值,然后再引入一条边N-N1,容量设为2,费用设为0,然后去求1到N1的最小费用最大流,如果到N1的流量为2,则输出最小费用,否则就是无…...
律师做几个网站/网站google搜索优化
#!/bin/bash #自动备份grafana数据库并上传到云盘 NOWDATEdate %Y-%m-%d YUNPAN_USERxxxx YUNPAN_PASSWDXXXXXXXXXX YUNPAN_SERVERhttps://yunpan.x.com/remote.php/webdav YUNPAN_DIRx/backup/grafana #建立备份基本目录环境 BACKUPDIR/x/data/backup/grafana [ -d ${BACKUPDI…...
淄博网站公司/网络营销渠道可分为哪些
猜字游戏是一款益智游戏,喜欢玩具有挑战性单词游戏的你就可以来体验一下了,给你一个字母板。尝试通过想象相邻字母的单词。您将获得一个分数,根据您使用的字母,你已经使用了多少个字母,并以这些字母相关联的任何修饰符…...
乌海网站建设/seo推广公司教程
一、介绍 早期的SSLv2根据经典的公钥基础设施PKI(Public Key Infrastructure)设计,它默认认为:一台服务器(或者说一个IP)只会提供一个服务,所以在SSL握手时,服务器端可以确信客户端申请的是哪张证书。 但是…...
忻州网站制作/东莞做网络推广的公司
错误号1368; 符号: ER_VIEW_NONUPD_CHECK; SQLSTATE: HY000消息:在不可更新的视图%s。%s上检查选项错误号1369; 符号: ER_VIEW_CHECK_FAILED; SQLSTATE: HY000消息:检查选项失败&…...
长沙的企业网站建设/关键词怎么选择技巧
逻辑简单,直接上代码。 #define _CRT_SECURE_NO_WARNINGS 1 //1.能够被4整除,但是不能被100整除的年份是闰年; //2.能够被400整除的年份是闰年#include<stdio.h> void leap_year_judge(int year)//判断闰年函数 {if ((year % 4 0 && yea…...