JavaScript入门⑨-异步编程●异世界之旅
JavaScript入门系列目录
- JavaScript入门①-基础知识筑基
- JavaScript入门②-函数(1)基础{浅出}
- JavaScript入门③-函数(2)原理{深入}执行上下文
- JavaScript入门④-万物皆对象:Object
- JavaScript入门⑤-欲罢不能的对象、原型与继承
- JavaScript入门⑥-WEB浏览器API
- JavaScript入门⑦-DOM操作大全
- JavaScript入门⑧-事件总结大全
- JavaScript入门⑨-异步编程●异世界之旅
- JavaScript入门⑩-ES6归纳总结
01、JS线程与事件循环
JavaScript的是单线程的语言,按顺序执行。事件循环(Event loop)是JS的运行机制,也是JS实现各种“异步”功能的基础。
1.1、浏览器进程
浏览器本身是多进程的(Edge/Chrome),在系统的的任务管理器中可以看到,只打开了一个页面,却有多个进程。其中渲染进程(浏览器内核)就是页面的管家,负责页面的渲染、脚本执行、事件等,每个页面(浏览器页签)会有一个独立的管家——渲染进程。
而在渲染进程中,又有多个线程,具有不同的职责,负责不同的事务。比如有定时器线程、HTTP请求线程、事件触发线程、渲染线程、JS引擎线程等,除了HTTP线程基本都是单线程。
- 定时器线程,就是用于管理
setTimeout
/setInterval
定时任务的,当到达指定时间了就把要执行的任务(函数)放到一个任务队列中,等待JS引擎去执行。so,定时器一般都不准,有一点延迟。也不能这么说,定时器并没有错,应该是队列和JS引擎的问题。 - HTTP请求线程,负责执行HTTP请求,包括各种资源加载。当请求完成、或请求的状态变化时,把触发的回调函数放入事件队列,交给JS线程去执行。
- GUI线程:负责浏览器页面的渲染,如解析HTML、CSS,构建DOM树,布局计算和绘制等。GUI线程和JS线程是互斥的,所以当JS执行一个长任务时,会造成页面UI的卡顿。
- 事件触发线程:用来控制事件的循环,各种事件首先是会在事件触发线程里处理,当满足条件触发事件执行时,把待执行的事件处理任务(函数)添加到JS的任务队列中。
- JS引擎线程(主线程):用于页面JavaScript代码的解析和执行。
1.2、JS的单线程与异步
JavaScript的是单线程的语言,一个页面渲染进程中只有一个JS线程,意味着同一时刻只能干一件事情,那么多的JS代码都必须顺序执行。
为什么采用单线程呢?核心目的是为保障DOM操作的一致性,避免同时操作DOM引起的渲染混乱,也可能就是为了便于实现。同时缺点也很明显,如果有长耗时操作时就会引起阻塞,导致页面卡顿。为了解决这个问题,JS执行代码有同步、异步两种模式,浏览器提供了多种异步编程方案。
异步编程方案 | 描述 |
---|---|
回调函数 | 最常用的一种异步模式,也是异步的基础。缺点是容易形成地狱回调 |
事件监听 | 绑定事件处理程序,触发执行 |
发布订阅模式 | 自定义(或第三方)一个消息中心,基于消息的发布、订阅来驱动 |
Promise(async/awit) | ES6支持的异步编程API,好用!async /awit 是其语法糖 |
生成器Generator/ yield | 基于生成器Generator的可暂停、恢复函数执行的特性 |
worker线程 | 正式的线程,可创建一个独立上下文环境的线程,和主线程采用消息通信 |
1.3、事件循环(Event Loop)
JS线程解析代码时,把一些异步任务交给其他工作线程去处理,如HTTP请求、事件、setTimeout
,这些工作线程处理完会把回调任务(函数)放到任务队列中给JS线程来执行。JS线程会一直轮询任务队列并进行处理,这就是JS的“事件循环(Event Loop)”。
- 任务(事件)队列:任务队列是一个先进先出的队列,它里面存放着各种待处理任务(代码/函数)。
- 事件循环:事件循环是指JS主线程循环从任务队列中获取任务、执行任务的过程。
事件循环(Event loop)是JS的运行机制,也是JS实现各种“异步”功能的基础。比如赫赫有名的延时方法setTimeout
,setTimeout(func,0)
(参数delay
=0)并不是真正立即执行,而是把func
放到一个任务队列里。如果JS引擎刚好有空,就会立即召唤他,否则就老老实实排队等候被轮。
一段setTimeout
代码:
setTimeout(function () {
console.log(1 + 1);
}, 3000);
- ① JS线程:
setTimeout(callback,timeout)
函数会调用定时器线程,把这个定时任务交给他。 - ② 定时器线程:我只是一个计时器,
timeout
时间到了,就把回调函数放入任务队列,由JS线程来执行。 - ③ JS线程:轮询任务队列(有空的时候),执行回调函数。
1.4、⌈宏/微⌋任务队列
上面说的JS任务队列,大致分为宏任务(macro task)队列、微任务(micro task)队列。
宏任务队列:JS引擎的任务队列,按顺序轮询排队执行,没有优先级,发生在渲染之前。
- 哪些任务:script整体代码、各种UI/IO事件任务、延时任务
setTimeout
/setInterval
、网络HTTP请求 等。 - 顺序轮询执行:不断轮询队列并执行:
- 执行任务时,永远不会进行渲染(render),与GUI线程互斥。
- 浏览器为了让JS内部宏任务与DOM操作能够有序的执行,会在一个宏任务执行结束后,下一个宏任务执行开始前,对页面进行重新渲染。
- 如果在执行一个长耗时任务,页面会“无响应”,可以拆分为多个子任务通过延时
setTimeout
执行。
微任务(Microtask):比宏任务优先级高的微任务,发生在宏任务之后、渲染之前:当执行完一个宏任务后优先执行(清空)所有微任务。
- 哪些任务:异步
Promise
创建的待执行.then/catch/finally
会成为微任务;通过方法queueMicrotask(func)
添加的任务(优先UI任务执行)。 - 优先执行:微任务会在执行任何其他事件处理、或渲染、或执行任何其他宏任务之前完成。微任务会被优先执行,不愧是超级无敌VIP会员。
console.log("sync-1");
setTimeout(() => console.log("timeout"), 0);
Promise.resolve()
.then(() => console.log("promise.then"))
.finally(() => console.log("promise.finally"));
queueMicrotask(() => console.log("queueMicrotask"));
console.log("sync-2");
// sync-1
// sync-2
// promise.then
// queueMicrotask
// promise.finally
// timeout
02、Promise异步编程
Promise(IE)是现代 JavaScript 中异步编程的基础,比传统的回调异步更强大、更简洁。Promise是一个对象,可以理解为一个容器,保存了一些异步操作(及执行的状态信息),并管理和调度这些异步操作。(Promise /ˈprɒmɪs/ 承诺)
2.1、基础语法
Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),状态是由异步操作执行结果决定的。
- 待定(pending):初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled):意味着操作成功成功。(fulfilled /fʊlˈfɪld/ 完成)
- 已拒绝(rejected):意味着操作失败。(rejected /rɪˈdʒektɪd/被拒绝)
Promise 的标准语法:
// 标准语法
let promise = new Promise(function (resolve, reject) {
//some code
if (true) //根据需要返回成功、失败的状态。
resolve("OK");
else
reject("failure"); //如果发生异常,会自动捕获并进行拒绝reject(error)处理
});
//链式操作
promise.then(successCallback, ?failureCallback)
.catch(func)
.finally(func);
Promise的构造函数参数 excutor (function(resolve, reject))
会自动运行。参数resolve
、reject
是Promise提供的回调,在合适的地方调用他们即可,不过每次只有一个有效,他决定了promise的状态。
- resolve(value) :任务成功并带有结果
value
,该结果值value
可传输给后续的异步函数。promise
状态为“已兑现(fulfilled)” - reject(error) :任务失败,返回错误信息。
promise
状态为“已拒绝(rejected)”
异步&微任务:
- Promise 的参数
excutor
是同步的,会立即执行。 - then()、catch()、finally()都是异步的,他们是在一个
promise
准备就绪后,被放到一个微任务队列里(microtask queue),等当前JS的任务执行完毕后,才开始执行这个队列中的任务。注意不是多线程,还是在JS线程里。
2.2、Promise方法-链式调用
Promise的属性方法:
静态属性/方法 | 描述 |
---|---|
Promise.all(iterable) | 执行一个promise集合,都成功或有一个失败返回一个新promise对象(返回值的数组) |
Promise.allSettled(iterable) | 等到所有 promise 都已敲定,返回的promise包含返回值数组 |
Promise.any(iterable) | 任意一个 promise 成功,就返回那个成功的 promise 的值。 |
Promise.race(iterable) | 任意一个 promise 敲定,返回那个promise对象 |
Promise.reject(reason) | 返回一个状态为已拒绝的 Promise 对象,并将给定的失败信息传递给对应的处理函数 |
Promise.resolve(value) | 如参数为普通数据,返回一个状态为成功的 Promise 对象。其他参数promise、thenable |
构造函数 | |
Promise(func(resolve, reject)) | 创建一个 Promise 对象,用于包装一个不支持异步的普通函数,这里的函数是同步执行的 |
实例属性 | 内置属性,不可访问 |
[[PromiseState]] | promise 的状态 |
[[PromiseResult]] | resolve 返回的值,或reject 返回的错误error 。 |
实例方法 | |
then(resolveFunc ,rejectFunc?) | 添加成功和失败的回调函数,实例promise 的状态决定调用哪个回调函数,参数2可空 |
catch(func(e)) | 添加一个被rejected 拒绝状态的回调函数,是then(null,rejectFunc) 的简写版本 |
finally() | 添加一个不管状态如何都会执行的回调,没有参数也没返回值,后面继续then 、catch |
Promise的then()
方法才是他的精髓,用于给promise
实例添加状态改变的回调函数,支持链式调用。
- 链式调用:
then()
、catch()
、finally()
都会返回新的promise
对象,所以它们可以被链式调用。 - 参数传递:
resolve
返回的值value
会作为参数传递给下一个then(func(value))
。
let p1 = new Promise((resolve, reject) => { resolve("0") });
p1=Promise.resolve('0'); //同上
p1.then(v => v + '1')
.then(v => v + '2')
.then(v => console.log(v)) //012
.catch(e => console.log(e))
.finally(() => console.log('end')); //end
2.3、异常处理
隐式的try...catch
:promise
中的所有函数都包含一个隐式的try...catch
,并对捕获的异常进行拒绝(rejection )处理。错误信息会一直“冒泡”传递,直到一个rejection
处理程序来处理。
- 被拒绝的
promise
会找最近的rejection
处理程序进行处理,如catch()
、then()
的的第二个参数,推荐专门的catch()
来捕获处理。 - 如果后面一直都没人处理这个异常,会触发一个全局window的
error
—— unhandledrejection。 catch()
处理完后可以继续链式执行then()
。
let p = Promise.resolve(1);
p.then(value => { return value + 1; })
.finally(() => console.log("休息一下!"))
.then(value => { return value + 1; })
.then(value => { console.log(value) })
.then(value => { throw new Error("着火了"); })
.catch(err => { console.log(err) })
.then(value => { console.log(value) }) //undefined,没有参数了
.finally(() => console.log("end"))
// 休息一下!
// 3
// Error: 着火了
// undefined
// end
2.4、async/await语法糖
await、async 是使用Promise更简易的一种语法糖,就像写同步代码,完全可以代替Promise
的语法形式。
- async function:
async
在函数申明前使用,让函数返回一个promise
异步对象,同时允许函数内使用await
。 - await promise(func),只在
async
内部工作,awit
会等待一个promise(func)
执行完成,再继续往下。类似promise.then
,他并不会阻塞CPU,是异步的。
//async 修饰的函数返回值包装成一个promise
async function doAsync() {
return 1;
return Promise.resolve(1); //效果同上
}
doAsync().then(console.log);
console.log('a');
//输出:a 1
async function doAsync2(num) {
try { //异常处理,同promise.catch
let n = await ((num) => { return num + 1; })(num)
n = await new Promise((resolve, reject) => {
setTimeout(() => { resolve(n + 1); }, 1000);
}) //等待返回结果,再往下执行
console.log(n); //3
await (() => { console.log("result:" + n) })(n); //result:3
}
catch (error)
{ console.log(error) }
}
doAsync2(1)
console.log('doAsync');
//输出:doAsync 3 result:3
03、生成器*Generator
什么是Generator?
- 她是一个迭代器,返回一个遍历器对象,符合可迭代协议和迭代器协议,可用
next()
、for(of)
迭代。 - 她是可控函数:内部代码可以自由控制暂停和继续执行。标准的函数是一次性执行完毕,直到末尾或
return
语句。而生成器的函数可以由yield
暂停执行(交出控制权),next()
恢复执行。 - 她是一个状态机,封装了多个内部状态。
- 她是异步任务管理容器,提供一种异步的实现方案。
3.1、基础语法
Generator 使用一个特殊的函数语法function*
(带星*
号)创建生成器generator
,调用生成器函数获得一个生成器对象,该对象的实例方法:
实例方法 | 描述 |
---|---|
next() | 恢复执行,返回一个由 yield 表达式生成的值:{value: 1, done: false} |
return(value?) | 返回给定的值并结束生成器,可提前中止生成器。 |
throw() | 向生成器抛出一个错误,生成器内部如没处理则会中止 |
//定义生成器
function* GeneratorN(s) {
console.log('yield-1');
yield s + 1;
console.log('yield-2');
yield s + 2;
console.log('yield-3');
return s + 3;
}
//创建生成器对象
var gn = GeneratorN(1);
//next()调用
console.log(gn.next()); //yield-1 {value: 2, done: false}
console.log(gn.next()); //yield-2 {value: 3, done: false}
console.log(gn.next()); //yield-3 {value: 4, done: true}
console.log(gn.next()); //{value: undefined, done: true}
定义生成器:function* generatorName(s) { }
- yield:在
generator
(仅在)内部,用yield
表达式申明一个需要返回的值。(yield /jiːld/ 收益) - return:非必须!作用是指定最后一次
next()
函数调用时的value
值,并标识迭代器状态完成done: true
。
使用:在外部调用迭代器函数,并不是执行函数,而是返回一个生成器对象generator object
。
- 生成器对象
generator
的主要方法就是next()
,当调用next()
方法时,执行代码到最近的yield <value>
语句,然后暂停,并返回yield
表达式的值。 next()
方法返回一个对象,表示当前阶段的信息:{value: 2, done: false}
- value 属性是
yield
语句后面表达式的值,表示当前阶段的值。- done 属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。已全部执行完成则为 true,否则为 false。
指针:generator
对象内部存在一个“指针”,指向代码暂停的地方,调用next()
方法时,从指针位置执行代码直到下一个yield
语句,指针会移到到该yield
语句末尾。
一个切换CSS状态的示例:
// 创建一个可无限循环的列表list
function* loop(list) {
let i = 0;
while (true) {
if (i >= list.length) i = 0;
yield list[i++];
}
}
function toggle(...actions) {
let gen = loop(actions);
return function (...args) {
return gen.next().value.apply(this, args);
}
}
// 绑定状态切换事件
switcher.addEventListener('click', toggle(
e => e.target.className = 'off',
e => e.target.className = 'warn',
e => e.target.className = 'on'
));
» 其他使用示例:
function* genAll() {
yield* [1, 2, 3]; //yield*:嵌套一个迭代对象,进入另一个生成器函数
let data = yield 'data:'; //申明接收一个next()参数,下次next(arg)的参数赋值给data
console.log(data);
}
let g = genAll();
console.log(g.next('a1')); //{value: 1, done: false}
console.log(g.next('a2')); //{value: 2, done: false}
console.log(g.next('a3')); //{value: 3, done: false}
console.log(g.next('a4')); //{value: 'data:', done: false}
console.log(g.next('a5')); //参数传入了:a5 {value: undefined, done: true}
console.log(g.next('a6')); //{value: undefined, done: true}
3.2、可迭代for(of)
迭代器对象是可迭代的,执行迭代时,自动调用next()
获取值,并判断状态done
。
- 可使用
for(of)
迭代获取所有next()
的值value
。 - 用展开操作符,展开所有所有
next()
的值value
。
function* GeneratorN(s) {
yield s + 1;
yield s + 2;
return s + 3;
}
//用for(of)遍历
for (let item of GeneratorN(100)) {
console.log(item); //101,102
}
//展开运算符,也没有return的值
console.log(...GeneratorN(10)); //11 12
忽略return值:当
done: true
时,for..of
循环会忽略最后一个 value,即只有yield
表达式返回的值才有效。
3.3、async异步迭代器*
由于迭代器的暂停、恢复执行的特点,让他成为了实现异步编程的一种方案。比如常用的ajax
请求处理数据:
function* addUserPoints(id, points) {
yield ajax('/api/points/', { id: id, points: points });
let user = yield ajax('/api/userinfo/', { id: id });
user.points += points;
yield ajax('/api/user/', user);
yield 'end';
}
结合异步async
/await
,就可以像同步代码一样写异步代码了。可以把整个 Generator 函数看作异步任务的容器,异步操作需要暂停的地方,都用 yield 语句注明。
- async:迭代器函数加
async
,申明为异步generator
,此时内部可以用await
了。 - await:用
await
去等待一个promise
操作,比如ajax请求。此时调用next()
返回的就是一个promise
了。
async function* genN(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 2000)); //一个等待2s的异步操作
yield i;
}
}
let g = genN(1, 5);
console.log('start');
for(let i=1;i<=5;i++){
g.next().then(v => console.log(v.value)); //注意g.next()返回的是一个异步promise,可用await
}
console.log('end');
//输出:
//start
//end
//1 2 3 4 5 6 //间隔2s输出
04、worker线程
Worker(IE10)可以创建独立的线程,前端终于有了正式的线程了,所以JS也就不再是单纯的“单线程”了。可以充分分担主线程的压力,也能发挥多CPU多核的优势了。可以把一些非UI操作的任务放在worker中来执行,再也不用担心UI卡顿了。
Worker 基于一个JS文件创建一个独立的线程,该JS文件代码运行在这个新线程中。该线程是独立于主线程的,其全局上下文不是window了,一般情况就是DedicatedWorkerGlobalScope,可用self
来访问。需要注意一些事项:
- 同源:和主线程遵循同源策略。
- 不可操作UI:包括窗口、文档DOM、页面元素,
alert()
、confirm()
也是不可用的。 - 消息通信:和主线程不在一个上下文环境,只能通过消息进行通信。
构造函数 | 描述 |
---|---|
Worker(jsUrl,options) | 创建一个专用 Web worker |
实例方法 | |
postMessage(message) | 向worker发生一个消息 |
terminate() | 立即终止 worker,是立即 |
事件 | |
onmessage=func(message) | 订阅worker的消息,消息在message.data 上 |
onerror=func(e) | 发生错误的异常事件 |
onmessageerror=func() | 消息解析错误的异常事件 |
操作步骤:
- 创建处理
worker
线程任务的JS文件,在JS文件中订阅消息事件用于接收消息指令。 - 基于该指定的JS文件创建worker线程,该JS文件代码会被执行。
- 订阅worder的消息通知,接收worker发送过来的消息。
- 给worker发送消息(指令),让他干活。
- worker收到的指令,并根据指令干活,干完后发送消息回去。
//********************** worker线程脚本 **********************//
console.log("kworker.js")
//接收消息,//这里的self是该工作线程的全局对象DedicatedWorkerGlobalScope,可以省略
self.addEventListener("message", message => {
self.receiveMessage(message.data);
//判断消息指令,开始干活
if (message.data == "摸鱼") {
console.log("kworker.js--摸鱼开始");
//do something
//发送消息到主线程
postMessage("摸鱼完毕");
}
})
function receiveMessage(mes) {
console.log('kworker.js--收到消息:', mes);
}
//********************** 主脚本 **********************//
console.log('创建worker线程');
//2基于指定的JS文件创建worker线程,该JS文件代码会被执行。
let thread = new Worker('../js/kworker.js');
//订阅发回来的消息
thread.onmessage = (mes) => console.log('主线程:',mes.data);
// 给wokder线程发送消息
thread.postMessage('呼叫');
thread.postMessage('摸鱼');
//********************** 输出 **********************//
// 创建worker线程
// kworker.js
// kworker.js--收到消息: 呼叫
// kworker.js--收到消息: 摸鱼
// kworker.js--摸鱼开始
// 主线程: 摸鱼完毕
参考资料
️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址-语雀
JavaScript入门⑨-异步编程●异世界之旅的更多相关文章
- [C#] 走进异步编程的世界 - 开始接触 async/await
走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $&qu ...
- [C#] 走进异步编程的世界 - 剖析异步方法(上)
走进异步编程的世界 - 剖析异步方法(上) 序 这是上篇<走进异步编程的世界 - 开始接触 async/await 异步编程>(入门)的第二章内容,主要是与大家共同深入探讨下异步方法. 本 ...
- [C#] 走进异步编程的世界 - 剖析异步方法(下)
走进异步编程的世界 - 剖析异步方法(下) 序 感谢大家的支持,这是昨天发布<走进异步编程的世界 - 剖析异步方法(上)>的补充篇. 目录 异常处理 在调用方法中同步等待任务 在异步方法中 ...
- [C#] 走进异步编程的世界 - 在 GUI 中执行异步操作
走进异步编程的世界 - 在 GUI 中执行异步操作 [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5877042.html 序 这是继<开始接 ...
- 走进异步编程的世界 - 开始接触 async/await
[C#] 走进异步编程的世界 - 开始接触 async/await 走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async ...
- [C#] 走进异步编程的世界 - 开始接触 async/await(转)
原文链接:http://www.cnblogs.com/liqingwen/p/5831951.html 走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 ...
- 走进异步编程的世界 - 开始接触 async/await(转)
序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $"" 来拼接字符串,相当于string.Fo ...
- 走进异步编程的世界 - 在 GUI 中执行异步操作
转载:https://www.cnblogs.com/liqingwen/p/5877042.html 走进异步编程的世界 - 在 GUI 中执行异步操作 [博主]反骨仔 [原文地址]http://w ...
- javascript的异步编程
同步与异步 介绍异步之前,回顾一下,所谓同步编程,就是计算机一行一行按顺序依次执行代码,当前代码任务耗时执行会阻塞后续代码的执行. 同步编程,即是一种典型的请求-响应模型,当请求调用一个函数或方法后, ...
- 走进异步编程的世界--async/await项目使用实战
起因:今天要做一个定时器任务:五分钟查询一次数据库发现超时未支付的订单数据将其状态改为已经关闭(数据量大约100条的情况) 开始未使用异步: public void SelfCloseGpPayOrd ...
随机推荐
- ELasticsearch忘记密码后重置超级用户密码
创建一个临时的超级用户TestSuper: [root@cfeea elasticsearch]# ./bin/elasticsearch-users useradd TestSuper -r sup ...
- 使用docker-compose部署WordPress项目
创建空文件夹 假设新建一个名为 wordpress 的文件夹,然后进入这个文件夹. 创建 docker-compose.yml 文件 docker-compose.yml 文件将开启一个 wordpr ...
- nsis插件nsisSlideshow.dll更新
更新至1.7版本,作者wiz0u已解决关于ie9的兼容问题.Good 下载地址: http://wiz0u.free.fr/prog/nsisSlideshow/latest.php
- slf4j、log4j2及logback使用
slf4j.log4j2及logback使用 1.问题来源 之前看过关于slf4j.log4j2及logback的介绍,slf4j是门面,log4j2及logback是具体实现,仅使用slf4j门面是 ...
- 图片 css剪切,等比例缩放
object-fit: cover; .img1 {//自定义图片宽高,并且等比例缩放 width: 200px; height: 400px; object-fit: cover; }
- TF-GNN踩坑记录(三)
引言 Batch size问题 在Tensorflow-GNN中使用batch size除了需要注意上面的链接问题之外,最近我在调试的发现,使用了merge_batch_to_components() ...
- Kafka 之producer拦截器(interceptor)
Kafka 之producer拦截器(interceptor) 一.拦截器原理 Producer拦截器(interceptor)是在Kafka 0.10版本被引入的,主要用于实现clients端的定制 ...
- day48-JDBC和连接池04
JDBC和连接池04 10.数据库连接池 10.1传统连接弊端分析 传统获取Connection问题分析 传统的 JDBC 数据库连接使用DriverManager来获取,每次向数据库建立连接的时候都 ...
- 知识图谱-生物信息学-医学顶刊论文(Briefings in Bioinformatics-2021):生物信息学中的图表示学习:趋势、方法和应用
4.(2021.6.24)Briefings-生物信息学中的图表示学习:趋势.方法和应用 论文标题: Graph representation learning in bioinformatics: ...
- 基于Seq2Seq和注意力机制的句子翻译
Seq2Seq(Attention) 目录 Seq2Seq(Attention) 1.理论 1.1 机器翻译 1.1.1 模型输出结果处理 1.1.2 BLEU得分 1.2 注意力模型 1.2.1 A ...