订单30分钟未支付自动取消怎么实现?
目录
了解需求
方案 1:数据库轮询
方案 2:JDK 的延迟队列
方案 3:时间轮算法
方案 4:redis 缓存
方案 5:使用消息队列
了解需求
在开发中,往往会遇到一些关于延时任务的需求。
例如
生成订单 30 分钟未支付,则自动取消
生成订单 60 秒后,给用户发短信
对上述的任务,我们给一个专业的名字来形容,那就是延时任务。那么这里就会产生一个问题,这个延时任务和定时任务的区别究竟在哪里呢?一共有如下几点区别
定时任务有明确的触发时间,延时任务没有
定时任务有执行周期,而延时任务在某事件触发后一段时间内执行,没有执行周期
定时任务一般执行的是批处理操作是多个任务,而延时任务一般是单个任务
下面,我们以判断订单是否超时为例,进行方案分析
方案 1:数据库轮询
思路
该方案通常是在小型项目中使用,即通过一个线程定时的去扫描数据库,通过订单时间来判断是否有超时的订单,然后进行 update 或 delete 等操作
实现
可以用 quartz 来实现的,简单介绍一下
maven 项目引入一个依赖如下所示
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.2.2</version>
</dependency>
调用 Demo 类 MyJob 如下所示
package com.rjzheng.delay1;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class MyJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {System.out.println("要去数据库扫描啦。。。");}
public static void main(String[] args) throws Exception {// 创建任务JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity("job1", "group1").build();// 创建触发器 每3秒钟执行一次Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group3").withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).repeatForever()).build();Scheduler scheduler = new StdSchedulerFactory().getScheduler();// 将任务及其触发器放入调度器scheduler.scheduleJob(jobDetail, trigger);// 调度器开始调度任务scheduler.start();}
}
运行代码,可发现每隔 3 秒,输出如下
要去数据库扫描啦。。。
优点
简单易行,支持集群操作
缺点
对服务器内存消耗大
存在延迟,比如你每隔 3 分钟扫描一次,那最坏的延迟时间就是 3 分钟
假设你的订单有几千万条,每隔几分钟这样扫描一次,数据库损耗极大
方案 2:JDK 的延迟队列
思路
该方案是利用 JDK 自带的 DelayQueue 来实现,这是一个无界阻塞队列,该队列只有在延迟期满的时候才能从中获取元素,放入 DelayQueue 中的对象,是必须实现 Delayed 接口的。
DelayedQueue 实现工作流程如下图所示
其中 Poll():获取并移除队列的超时元素,没有则返回空
take():获取并移除队列的超时元素,如果没有则 wait 当前线程,直到有元素满足超时条件,返回结果。
实现
定义一个类 OrderDelay 实现 Delayed,代码如下
package com.rjzheng.delay2;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class OrderDelay implements Delayed {
private String orderId;
private long timeout;
OrderDelay(String orderId, long timeout) {this.orderId = orderId;this.timeout = timeout + System.nanoTime();}
public int compareTo(Delayed other) {if (other == this) {return 0;}OrderDelay t = (OrderDelay) other;long d = (getDelay(TimeUnit.NANOSECONDS) - t.getDelay(TimeUnit.NANOSECONDS));return (d == 0) ? 0 : ((d < 0) ? -1 : 1);}
// 返回距离你自定义的超时时间还有多少public long getDelay(TimeUnit unit) {return unit.convert(timeout - System.nanoTime(), TimeUnit.NANOSECONDS);}
void print() {System.out.println(orderId + "编号的订单要删除啦。。。。");}
}
运行的测试 Demo 为,我们设定延迟时间为 3 秒
package com.rjzheng.delay2;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.TimeUnit;
public class DelayQueueDemo {
public static void main(String[] args) {List<String> list = new ArrayList<String>();list.add("00000001");list.add("00000002");list.add("00000003");list.add("00000004");list.add("00000005");
DelayQueue<OrderDelay> queue = newDelayQueue < OrderDelay > ();long start = System.currentTimeMillis();for (int i = 0; i < 5; i++) {//延迟三秒取出queue.put(new OrderDelay(list.get(i), TimeUnit.NANOSECONDS.convert(3, TimeUnit.SECONDS)));try {queue.take().print();System.out.println("After " + (System.currentTimeMillis() - start) + " MilliSeconds");} catch (InterruptedException e) {e.printStackTrace();}}}
}
输出如下
00000001编号的订单要删除啦。。。。
After 3003 MilliSeconds
00000002编号的订单要删除啦。。。。
After 6006 MilliSeconds
00000003编号的订单要删除啦。。。。
After 9006 MilliSeconds
00000004编号的订单要删除啦。。。。
After 12008 MilliSeconds
00000005编号的订单要删除啦。。。。
After 15009 MilliSeconds
可以看到都是延迟 3 秒,订单被删除
优点
效率高,任务触发时间延迟低。
缺点
服务器重启后,数据全部消失,怕宕机
集群扩展相当麻烦
因为内存条件限制的原因,比如下单未付款的订单数太多,那么很容易就出现 OOM 异常
代码复杂度较高
方案 3:时间轮算法
思路
先上一张时间轮的图(这图到处都是啦)
时间轮算法可以类比于时钟,如上图箭头(指针)按某一个方向按固定频率轮动,每一次跳动称为一个 tick。这样可以看出定时轮由个 3 个重要的属性参数,ticksPerWheel(一轮的 tick 数),tickDuration(一个 tick 的持续时间)以及 timeUnit(时间单位),例如当 ticksPerWheel=60,tickDuration=1,timeUnit=秒,这就和现实中的始终的秒针走动完全类似了。
如果当前指针指在 1 上面,我有一个任务需要 4 秒以后执行,那么这个执行的线程回调或者消息将会被放在 5 上。那如果需要在 20 秒之后执行怎么办,由于这个环形结构槽数只到 8,如果要 20 秒,指针需要多转 2 圈。位置是在 2 圈之后的 5 上面(20 % 8 + 1)
实现
我们用 Netty 的 HashedWheelTimer 来实现
给 Pom 加上下面的依赖
<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.24.Final</version>
</dependency>
测试代码 HashedWheelTimerTest 如下所示
package com.rjzheng.delay3;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.Timer;
import io.netty.util.TimerTask;
import java.util.concurrent.TimeUnit;
public class HashedWheelTimerTest {
static class MyTimerTask implements TimerTask {
boolean flag;
public MyTimerTask(boolean flag) {this.flag = flag;}
public void run(Timeout timeout) throws Exception {System.out.println("要去数据库删除订单了。。。。");this.flag = false;}}
public static void main(String[] argv) {MyTimerTask timerTask = new MyTimerTask(true);Timer timer = new HashedWheelTimer();timer.newTimeout(timerTask, 5, TimeUnit.SECONDS);int i = 1;while (timerTask.flag) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(i + "秒过去了");i++;}}
}
输出如下
1秒过去了
2秒过去了
3秒过去了
4秒过去了
5秒过去了
要去数据库删除订单了。。。。
6秒过去了
优点
效率高,任务触发时间延迟时间比 delayQueue 低,代码复杂度比 delayQueue 低。
缺点
服务器重启后,数据全部消失,怕宕机
集群扩展相当麻烦
因为内存条件限制的原因,比如下单未付款的订单数太多,那么很容易就出现 OOM 异常
方案 4:redis 缓存
思路一
利用 redis 的 zset,zset 是一个有序集合,每一个元素(member)都关联了一个 score,通过 score 排序来取集合中的值
添加元素:ZADD key score member [score member …]
按顺序查询元素:ZRANGE key start stop [WITHSCORES]
查询元素 score:ZSCORE key member
移除元素:ZREM key member [member …]
测试如下
添加单个元素
redis> ZADD page_rank 10 google.com
(integer) 1
添加多个元素
redis> ZADD page_rank 9 baidu.com 8 bing.com
(integer) 2
redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "baidu.com"
4) "9"
5) "google.com"
6) "10"
查询元素的score值
redis> ZSCORE page_rank bing.com
"8"
移除单个元素
redis> ZREM page_rank google.com
(integer) 1
redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "baidu.com"
4) "9"
那么如何实现呢?我们将订单超时时间戳与订单号分别设置为 score 和 member,系统扫描第一个元素判断是否超时,具体如下图所示
实现一
package com.rjzheng.delay4;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Tuple;
import java.util.Calendar;
import java.util.Set;
public class AppTest {
private static final String ADDR = "127.0.0.1";
private static final int PORT = 6379;
private static JedisPool jedisPool = new JedisPool(ADDR, PORT);
public static Jedis getJedis() {return jedisPool.getResource();}
//生产者,生成5个订单放进去public void productionDelayMessage() {for (int i = 0; i < 5; i++) {//延迟3秒Calendar cal1 = Calendar.getInstance();cal1.add(Calendar.SECOND, 3);int second3later = (int) (cal1.getTimeInMillis() / 1000);AppTest.getJedis().zadd("OrderId", second3later, "OID0000001" + i);System.out.println(System.currentTimeMillis() + "ms:redis生成了一个订单任务:订单ID为" + "OID0000001" + i);}}
//消费者,取订单
public void consumerDelayMessage() {Jedis jedis = AppTest.getJedis();while (true) {Set<Tuple> items = jedis.zrangeWithScores("OrderId", 0, 1);if (items == null || items.isEmpty()) {System.out.println("当前没有等待的任务");try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}continue;}int score = (int) ((Tuple) items.toArray()[0]).getScore();Calendar cal = Calendar.getInstance();int nowSecond = (int) (cal.getTimeInMillis() / 1000);if (nowSecond >= score) {String orderId = ((Tuple) items.toArray()[0]).getElement();jedis.zrem("OrderId", orderId);System.out.println(System.currentTimeMillis() + "ms:redis消费了一个任务:消费的订单OrderId为" + orderId);}}}
public static void main(String[] args) {AppTest appTest = new AppTest();appTest.productionDelayMessage();appTest.consumerDelayMessage();}
}
此时对应输出如下
可以看到,几乎都是 3 秒之后,消费订单。
然而,这一版存在一个致命的硬伤,在高并发条件下,多消费者会取到同一个订单号,我们上测试代码 ThreadTest
package com.rjzheng.delay4;
import java.util.concurrent.CountDownLatch;
public class ThreadTest {
private static final int threadNum = 10;private static CountDownLatch cdl = newCountDownLatch(threadNum);
static class DelayMessage implements Runnable {public void run() {try {cdl.await();} catch (InterruptedException e) {e.printStackTrace();}AppTest appTest = new AppTest();appTest.consumerDelayMessage();}}
public static void main(String[] args) {AppTest appTest = new AppTest();appTest.productionDelayMessage();for (int i = 0; i < threadNum; i++) {new Thread(new DelayMessage()).start();cdl.countDown();}}
}
输出如下所示
显然,出现了多个线程消费同一个资源的情况。
解决方案
(1)用分布式锁,但是用分布式锁,性能下降了,该方案不细说。
(2)对 ZREM 的返回值进行判断,只有大于 0 的时候,才消费数据,于是将 consumerDelayMessage()方法里的
if(nowSecond >= score){String orderId = ((Tuple)items.toArray()[0]).getElement();jedis.zrem("OrderId", orderId);System.out.println(System.currentTimeMillis()+"ms:redis消费了一个任务:消费的订单OrderId为"+orderId);
}
修改为
if (nowSecond >= score) {String orderId = ((Tuple) items.toArray()[0]).getElement();Long num = jedis.zrem("OrderId", orderId);if (num != null && num > 0) {System.out.println(System.currentTimeMillis() + "ms:redis消费了一个任务:消费的订单OrderId为" + orderId);}
}
在这种修改后,重新运行 ThreadTest 类,发现输出正常了
思路二
该方案使用 redis 的 Keyspace Notifications,中文翻译就是键空间机制,就是利用该机制可以在 key 失效之后,提供一个回调,实际上是 redis 会给客户端发送一个消息。是需要 redis 版本 2.8 以上。
实现二
在 redis.conf 中,加入一条配置
notify-keyspace-events Ex
运行代码如下
package com.rjzheng.delay5;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPubSub;
public class RedisTest {
private static final String ADDR = "127.0.0.1";private static final int PORT = 6379;private static JedisPool jedis = new JedisPool(ADDR, PORT);private static RedisSub sub = new RedisSub();
public static void init() {new Thread(new Runnable() {public void run() {jedis.getResource().subscribe(sub, "__keyevent@0__:expired");}}).start();}
public static void main(String[] args) throws InterruptedException {init();for (int i = 0; i < 10; i++) {String orderId = "OID000000" + i;jedis.getResource().setex(orderId, 3, orderId);System.out.println(System.currentTimeMillis() + "ms:" + orderId + "订单生成");}}
static class RedisSub extends JedisPubSub {@Overridepublic void onMessage(String channel, String message) {System.out.println(System.currentTimeMillis() + "ms:" + message + "订单取消");
}}
}
输出如下
可以明显看到 3 秒过后,订单取消了
ps:redis 的 pub/sub 机制存在一个硬伤,官网内容如下
原:Because Redis Pub/Sub is fire and forget currently there is no way to use this feature if your application demands reliable notification of events, that is, if your Pub/Sub client disconnects, and reconnects later, all the events delivered during the time the client was disconnected are lost.
翻: Redis 的发布/订阅目前是即发即弃(fire and forget)模式的,因此无法实现事件的可靠通知。也就是说,如果发布/订阅的客户端断链之后又重连,则在客户端断链期间的所有事件都丢失了。因此,方案二不是太推荐。当然,如果你对可靠性要求不高,可以使用。
优点
(1) 由于使用 Redis 作为消息通道,消息都存储在 Redis 中。如果发送程序或者任务处理程序挂了,重启之后,还有重新处理数据的可能性。
(2) 做集群扩展相当方便
(3) 时间准确度高
缺点
需要额外进行 redis 维护
方案 5:使用消息队列
思路
我们可以采用 rabbitMQ 的延时队列。RabbitMQ 具有以下两个特性,可以实现延迟队列
RabbitMQ 可以针对 Queue 和 Message 设置 x-message-tt,来控制消息的生存时间,如果超时,则消息变为 dead letter
lRabbitMQ 的 Queue 可以配置 x-dead-letter-exchange 和 x-dead-letter-routing-key(可选)两个参数,用来控制队列内出现了 deadletter,则按照这两个参数重新路由。结合以上两个特性,就可以模拟出延迟消息的功能,具体的,我改天再写一篇文章,这里再讲下去,篇幅太长。
优点
高效,可以利用 rabbitmq 的分布式特性轻易的进行横向扩展,消息支持持久化增加了可靠性。
缺点
本身的易用度要依赖于 rabbitMq 的运维.因为要引用 rabbitMq,所以复杂度和成本变高。
相关文章:
订单30分钟未支付自动取消怎么实现?
目录了解需求方案 1:数据库轮询方案 2:JDK 的延迟队列方案 3:时间轮算法方案 4:redis 缓存方案 5:使用消息队列了解需求在开发中,往往会遇到一些关于延时任务的需求。例如生成订单 30 分钟未支付࿰…...
< 开源项目框架:推荐几个开箱即用的开源管理系统 - 让开发不再复杂 >
文章目录👉 SCUI Admin 中后台前端解决方案👉 Vue .NetCore 前后端分离的快速发开框架👉 next-admin 适配移动端、pc的后台模板👉 django-vue-admin-pro 快速开发平台👉 Admin.NET 通用管理平台👉 RuoYi 若…...
内网渗透-基础环境
解决依赖,scope安装 打开要给cmd powershell 打开远程 Set-ExecutionPolicy RemoteSigned -scope CurrentUser; 我试了好多装这东西还是得科学上网,不然不好用 iwr -useb get.scoop.sh | iex 查看下载过的软件 安装sudo 安装git 这里一定要配置bu…...
Go语言学习的第一天(对于Go学习的认识和工具选择及环境搭建)
首先学习一门新的语言,我们要知道这门语言可以帮助我们做些什么?为什么我们要学习这门语言?就小wei而言学习这门语言是为了区块链,因为自身是php出身,因为php的一些特性只能通过一些算法模拟的做一个虚拟链,…...
C和C++到底有什么关系
C++ 读作”C加加“,是”C Plus Plus“的简称。顾名思义,C++是在C的基础上增加新特性,玩出了新花样,所以叫”C Plus Plus“,就像 iPhone 6S 和 iPhone 6、Win10 和 Win7 的关系。 C语言是1972年由美国贝尔实验室研制成功的,在当时算是高级语言,它的很多新特性都让汇编程序…...
14个Python处理Excel的常用操作,非常好用
自从学了Python后就逼迫用Python来处理Excel,所有操作用Python实现。目的是巩固Python,与增强数据处理能力。 这也是我写这篇文章的初衷。废话不说了,直接进入正题。 数据是网上找到的销售数据,长这样: 一、关联公式:…...
async/await 用法
1. 什么是 async/await async/await 是 ES8(ECMAScript 2017)引入的新语法,用来简化 Promise 异步操作。在 async/await 出 现之前,开发者只能通过链式 .then() 的方式处理 Promise 异步操作。示例代码如下: import …...
好意外,发现永久免费使用的云服务器
原因就不说了,说一下过程,在百度搜pythonIDE的时候,发现了一个网站 https://lightly.teamcode.com/https://lightly.teamcode.com/ 就是这个网站,看见这个免费试用,一开始觉得没什么,在尝试使用的过程中发…...
VSCode使用技巧,代码编写效率提升2倍以上!
VSCode是一款开源免费的跨平台文本编辑器,它的可扩展性和丰富的功能使得它成为了许多程序员的首选编辑器。在本文中,我将分享一些VSCode的使用技巧,帮助您更高效地使用它。 1. 插件 VSCode具有非常丰富的插件生态系统,通过安装插…...
SQL执行过程详解
1 、用户在客户端执行 SQL 语句时,客户端把这条 SQL 语句发送给服务端,服务端的进程,会处理这条客户端的SQL语句。 2 、服务端进程收集到SQL信息后,会在进程全局区PGA 中分配所需内存,存储相关的登录信息等。 3 、客…...
【物联网NodeJs-5天学习】第四天存储篇⑤ ——PM2,node.js应用进程管理器
【NodeJs-5天学习】第四天存储篇⑤ ——PM2,node.js应用进程管理器1. 前言2. 官方说明3. 安装PM24. PM2常用命令4.1 启动命令4.2 重新启动命令4.3 热重载命令4.4 停止命令4.5 删除命令4.6 查看进程运行状态4.4 显示某一个进程的具体信息4.8 显示日志信息4.9 终端监控…...
【C++学习】【STL】deque容器
dequeDouble Ended Queues(双向队列)deque和vector很相似,但是它允许在容器头部快速插入和删除(就像在尾部一样)。所耗费的时间复杂度也为常数阶O(1)。并且更重要的一点是,deque 容器中存储元素并不能保证所有元素都存储到连续的内…...
当 App 有了系统权限,真的可以为所欲为?
看到群里发了两篇文章,出于好奇,想看看这些个 App 在利用系统漏洞获取系统权限之后,都干了什么事,于是就有了这篇文章。由于准备仓促,有些 Code 没有仔细看,感兴趣的同学可以自己去研究研究,多多…...
vue3.js的介绍
一.vue.js简述 Vue是一套用于构建用户开源的MVVM结构的Javascript渐进式框架,尤雨溪在2015年10月27日发布了vue.js 1.0Eavangelion版本,在2016年9月30日发布了2.0Ghost in the Shell版本,目前项目由官方负责 vue的核心只关注图层࿰…...
【Three.js】shader特效 能量盾
shader特效之能量盾前言效果噪点图主要代码index.htmldepth-fs.jsdepth-vs.jsshield-fs.jsshield-vs.js相关项目前言 效果噪点图 为了可以自定义能量球的效果,这里使用外部加载来的噪点图做纹理,省去用代码写特效的过程。 主要代码 index.html <…...
【6000字长文】需求评审总是被怼?强烈推荐你试试这三招
前段时间和一个合作部门的产品新人沟通需求,结束的时候,他问了我一个问题,“你在产品新人阶段,最害怕做的事情是什么”? 我不假思索的回答说,“需求评审,是曾经最不想面对的环节,甚至在评审之前几个小时就开始心跳加速了。当然这也是产品修炼路上的必经之路,其实只要掌…...
Hive介绍及DDL
1.OLTP和OLAP OLTP: 联机事务处理系统。在前台接收的用户数据可以立即传送到后台进行处理,并在很短的时间内给出处理结果。关系型数据库是OLTP典型应用,如MySQL OLTP环境开展数据分析是否可行? 为了更好的开展数据分析&#x…...
Simulink 自动代码生成电机控制:在某国产ARM0定点MCU上实现自动代码生成无感电机控制
目录 前言 开发流程 定点化的技巧 代码生成运行演示 总结 前言 这次尝试了在国产arm0内核的MCU上实现Simulink自动代码生成永磁同步电机无传感控制。机缘巧合之下拿到了一块国产MCU的电机控制板和一个5000RPM的小电机。最后实现了无传感控制,在这里总结下一些经…...
MySQL基本查询
文章目录表的增删查改Create(创建)单行数据 全列插入多行数据 指定列插入插入否则更新替换Retrieve(读取)SELECT列全列查询指定列查询查询字段为表达式查询结果指定别名结果去重WHERE 条件基本比较BETWEEN AND 条件连接OR 条件连…...
你需要知道的 7 个 Vue3 技巧
VNode 钩子在每个组件或html标签上,我们可以使用一些特殊的(文档没写的)钩子作为事件监听器。这些钩子有:onVnodeBeforeMountonVnodeMountedonVnodeBeforeUpdateonVnodeUpdatedonVnodeBeforeUnmountonVnodeUnmounted我主要是在组件…...
行政区划获取
行政区划获取一、导入jar包二、代码展示背景:公司的行政区划代码有问题,有的没有街道信息,有的关联信息有误,然后找到了国家的网站国家统计局-行政区划,这个里面是包含了所有的行政信息,但是全是html页面&a…...
让ChatGPT介绍一下ChatGPT
申请新必应内测通过了,我在New Bing中使用下ChatGPT,让ChatGPT介绍一下ChatGPT 问题1:帮我生成一篇介绍chatGPT的文章,不少于2000字 回答: chatGPT是什么?它有什么特点和用途? chatGPT是一种…...
【Redis】Redis 主从复制 + 读写分离
Redis 主从复制 读写分离1. Redis 主从复制 读写分离介绍1.1 从数据持久化到服务高可用1.2 主从复制1.3 如何保证主从数据一致性?1.4 为何采用读写分离模式?2. 一主两从环境准备2.1 配置文件2.2 启动 Redis3. 主从复制原理3.1 全量同步3.1.1 建立连接3…...
2023届秋招,鬼知道我经历了什么
仅记录个人经历,充满主观感受,甚至纯属虚构,仅供参考,杠就是你对 本想毕业再写,但是考虑到等毕业了,24秋招的提前批就快开始了,大概就来不及了,正好现在有点时间,陆陆续…...
ChatGPT助力校招----面试问题分享(一)
1 ChatGPT每日一题:期望薪资是多少 问题:面试官问期望薪资是多少,如何回答 ChatGPT:当面试官问及期望薪资时,以下是一些建议的回答方法: 1、调查市场行情:在回答之前,可以先调查一…...
CSS媒体查询@media (prefers-color-scheme:dark)判断系统白天黑夜模式
前言 在最近学习中突然看到了在媒体查询中prefers-color-scheme:dark监听的使用,然后就模仿里边写了个简单例子,代码如下: body {background-color: #f5f5f5;}media (prefers-color-scheme: dark) {body {background-color: #666;}}然后通过…...
运行YOLOv8实现识别
https://github.com/ultralytics/ultralyticshttps://docs.ultralytics.com/环境配置官方环境要求Python>3.7(我是python3.8也是可以用的) environment with PyTorch>1.7.这是ultralyticsCommand Line Interface命令行接口运行输入参数的格式yolo …...
如何在Linux中优雅的使用 head 命令,用来看日志简直溜的不行
当您在 Linux 的命令行上工作时,有时希望快速查看文件的第一行,例如,有个日志文件不断更新,希望每次都查看日志文件的前 10 行。很多朋友使用文本编辑的命令是vim,但还有个命令head也可以让轻松查看文件的第一行。 在…...
Nginx.conf 配置详解
#安全问题,建议用nobody,不要用root. #user nobody; #worker数和服务器的cpu数相等是最为适宜 worker_processes 2; #work绑定cpu(4 work绑定4cpu) worker_cpu_affinity 0001 0010 0100 1000 #error_log path(存放路径) level(日志等级) path表示日志路径&…...
剖析NLP历史,看chatGPT的发展
1、NLP历史演进 1.1 NLP有监督范式 NLP里的有监督任务的范式,可以归纳成如下的样子。 输入是字词序列,中间一步关键的是语义表征,有了语义表征之后,然后交给下游的模型学习。所以预训练技术的发展,都是在围绕怎么…...
网站 绝对路径/百度点击快速排名
What happened 在开发的时候,遇到一个问题: 项目代码是在python3的环境下写的,但是,在终端中使用 flask run 运行项目时,使用的却是python2环境,导致很多包需要重新安装,甚至有些包安装不了。…...
在酒店做那个网站好/白山网络推广
Spring简介 Spring是目前最流行的Java开发框架 Spring下面有好多个子项目 关于数据库,安全都有不同的子项目支撑 所有项目的底层就是Spring框架 这篇文章讲SpringBoot 流程 SpringBoot 要求 流程步骤 1.创建模块 2.写一个请求处理类-和方法 从普通类到请求处…...
门户网站英文版建设/站长工具 站长之家
电容屏驱动调试先了解Linux电容屏驱动中几个常用的概念:中断下半部-工作队列; input机制; Linux与Android 多点触摸协议。一、中断下半部-工作队列 1、中断 先看一下宋宝华先生的《Linux设备驱动开发详解》里面…...
手机做网站过程/网站seo关键词排名查询
源码解压以后,我们可以看到以下的文件和文件夹: cpu 与处理器相关的文件。每个子目录中都包括 cpu.c和 interrupt.c、start.S、u-boot.lds。 cpu.c 初始化 CPU、设置指令 Cache和数据 Cache 等 interrupt.c 设置系统的各种中断和异常 start.S 是 U-boot…...
淄博网站定制/seo优化的主要任务包括
go操作elasticsearch 使用第三方库https://github.com/olivere/elastic来连接ES并进行操作。 下载与你的ES相同版本的client,例如我们这里使用的ES是7.2.1的版本,那么我们下载的client也要与之对应为github.com/olivere/elastic/v7。 使用go.mod来管理…...
怎么设网站/推广普通话的内容简短
数据结构是一个字典,每个值都是另一个字典,如:>>> from lib import schedule>>> schedule schedule.Schedule()>>> game schedule.games[0]>>> game.home>>> game.home.lineup{guerv001: {HR…...