对dubbo的DubboReference.check的参数进行剖析

背景

在使用dubbo的时候,发现当消费者启动的时候,如果提供者没有启动,即使提供者后来启动了,消费者也调不通提供者提供的接口了。

注册中心使用都是nacos

dubbo版本是3.0.4

例子

接口

public interface DemoService {String sayHello();
}

提供者

@DubboService
public class DemoServiceImpl implements DemoService {@Overridepublic String sayHello() {return "hello";}
}@EnableDubbo
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class ReferenceCheckProviderStarter {public static void main(String[] args) {new SpringApplicationBuilder(ReferenceCheckProviderStarter.class).web(WebApplicationType.NONE) // .REACTIVE, .SERVLET.run(args);System.out.println("dubbo service started");}
}

消费者

@EnableDubbo
@RestController
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class ReferenceCheckConsumerStarter {@DubboReferenceprivate DemoService demoService;@GetMapping("/dubbo/nacos/test")public Object test() {return demoService.sayHello();}public static void main(String[] args) {SpringApplication.run(ReferenceCheckConsumerStarter.class, args);}
}

1. 先启动provider,再启动consumer

a. 启动provider
 


nacos出现provider的服务

b. 启动consumer
 


nacos出现consumer的服务

访问 http://127.0.0.1:8080/dubbo/nacos/test 后返回hello

c. 终止provider
 


nacos上provider的服务消失了

访问 http://127.0.0.1:8080/dubbo/nacos/test 后返回No provider available from registry

d. 重新启动provider
 


nacos出现provider的服务

访问 http://127.0.0.1:8080/dubbo/nacos/test 后返回hello

可以看出:先启动provider,再启动consumer,整个过程是没问题。

2. 先启动consumer,再启动provider

a. 启动consumer
 


 

 


nacos出现consumer的服务,但立即又消失了

b. 启动provider
 


nacos出现provider的服务

访问 http://127.0.0.1:8080/dubbo/nacos/test 后返回Directory already destroyed .

可以看出:当consumer先启动时,如果provider此时没有启动,consumer就再也访问不到provider的服务了。

3. 先启动consumer,再启动provider (check=false)

修改一下注解@DubboRefere的参数

@DubboReference(check = false)
private DemoService demoService;

a. 启动consumer
 

 


nacos出现consumer的服务

访问 http://127.0.0.1:8080/dubbo/nacos/test 后返回
No provider available from registry

b. 启动provider
 


nacos出现provider的服务

访问 http://127.0.0.1:8080/dubbo/nacos/test 后返回
hello

可以看出:即使是consumer先启动,当provider启动后,consumer还是能够访问到provider的服务的。

关于报错

org.apache.dubbo.rpc.RpcException: No provider available from registry

public class RegistryDirectory<T> extends DynamicDirectory<T> {
@Overridepublic List<Invoker<T>> doList(Invocation invocation) {if (forbidden) {// 1. No service provider 2. Service providers are disabledthrow new RpcException(RpcException.FORBIDDEN_EXCEPTION, "No provider available from registry " +getUrl().getAddress() + " for service " + getConsumerUrl().getServiceKey() + " on consumer " +NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() +", please check status of providers(disabled, not registered or in blacklist).");}// ......}
}
public class RegistryDirectory<T> extends DynamicDirectory<T> {String EMPTY_PROTOCOL = "empty";private void refreshInvoker(List<URL> invokerUrls) {Assert.notNull(invokerUrls, "invokerUrls should not be null");if (invokerUrls.size() == 1&& invokerUrls.get(0) != null&& EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) {this.forbidden = true; // Forbid to accessthis.invokers = Collections.emptyList();routerChain.setInvokers(this.invokers);destroyAllInvokers(); // Close all invokers} else {this.forbidden = false; // Allow to accessif (invokerUrls == Collections.<URL>emptyList()) {invokerUrls = new ArrayList<>();}if (invokerUrls.isEmpty() && this.cachedInvokerUrls != null) {invokerUrls.addAll(this.cachedInvokerUrls);} else {this.cachedInvokerUrls = new HashSet<>();this.cachedInvokerUrls.addAll(invokerUrls);//Cached invoker urls, convenient for comparison}if (invokerUrls.isEmpty()) {return;}// can't use local reference because this.urlInvokerMap might be accessed at isAvailable() by main thread concurrently.Map<URL, Invoker<T>> oldUrlInvokerMap = null;if (this.urlInvokerMap != null) {// the initial capacity should be set greater than the maximum number of entries divided by the load factor to avoid resizing.oldUrlInvokerMap = new LinkedHashMap<>(Math.round(1 + this.urlInvokerMap.size() / DEFAULT_HASHMAP_LOAD_FACTOR));this.urlInvokerMap.forEach(oldUrlInvokerMap::put);}Map<URL, Invoker<T>> newUrlInvokerMap = toInvokers(oldUrlInvokerMap, invokerUrls);// Translate url list to Invoker map/*** If the calculation is wrong, it is not processed.** 1. The protocol configured by the client is inconsistent with the protocol of the server.*    eg: consumer protocol = dubbo, provider only has other protocol services(rest).* 2. The registration center is not robust and pushes illegal specification data.**/if (CollectionUtils.isEmptyMap(newUrlInvokerMap)) {logger.error(new IllegalStateException("urls to invokers error .invokerUrls.size :" + invokerUrls.size() + ", invoker.size :0. urls :" + invokerUrls.toString()));return;}List<Invoker<T>> newInvokers = Collections.unmodifiableList(new ArrayList<>(newUrlInvokerMap.values()));// pre-route and build cache, notice that route cache should build on original Invoker list.// toMergeMethodInvokerMap() will wrap some invokers having different groups, those wrapped invokers not should be routed.routerChain.setInvokers(newInvokers);this.invokers = multiGroup ? toMergeInvokerList(newInvokers) : newInvokers;this.urlInvokerMap = newUrlInvokerMap;try {destroyUnusedInvokers(oldUrlInvokerMap, newUrlInvokerMap); // Close the unused Invoker} catch (Exception e) {logger.warn("destroyUnusedInvokers error. ", e);}// notify invokers refreshedthis.invokersChanged();}}private synchronized void refreshOverrideAndInvoker(List<URL> urls) {// mock zookeeper://xxx?mock=return nulloverrideDirectoryUrl();refreshInvoker(urls);}@Overridepublic synchronized void notify(List<URL> urls) {if (isDestroyed()) {return;}Map<String, List<URL>> categoryUrls = urls.stream().filter(Objects::nonNull).filter(this::isValidCategory).filter(this::isNotCompatibleFor26x).collect(Collectors.groupingBy(this::judgeCategory));List<URL> configuratorURLs = categoryUrls.getOrDefault(CONFIGURATORS_CATEGORY, Collections.emptyList());this.configurators = Configurator.toConfigurators(configuratorURLs).orElse(this.configurators);List<URL> routerURLs = categoryUrls.getOrDefault(ROUTERS_CATEGORY, Collections.emptyList());toRouters(routerURLs).ifPresent(this::addRouters);// providersList<URL> providerURLs = categoryUrls.getOrDefault(PROVIDERS_CATEGORY, Collections.emptyList());// 3.x added for extend URL addressExtensionLoader<AddressListener> addressListenerExtensionLoader = getUrl().getOrDefaultModuleModel().getExtensionLoader(AddressListener.class);List<AddressListener> supportedListeners = addressListenerExtensionLoader.getActivateExtension(getUrl(), (String[]) null);if (supportedListeners != null && !supportedListeners.isEmpty()) {for (AddressListener addressListener : supportedListeners) {providerURLs = addressListener.notify(providerURLs, getConsumerUrl(),this);}}refreshOverrideAndInvoker(providerURLs); // 这里}}
public abstract class AbstractRegistry implements Registry {/*** Notify changes from the Provider side.** @param url      consumer side url* @param listener listener* @param urls     provider latest urls*/protected void notify(URL url, NotifyListener listener, List<URL> urls) {if (url == null) {throw new IllegalArgumentException("notify url == null");}if (listener == null) {throw new IllegalArgumentException("notify listener == null");}if ((CollectionUtils.isEmpty(urls))&& !ANY_VALUE.equals(url.getServiceInterface())) {logger.warn("Ignore empty notify urls for subscribe url " + url);return;}if (logger.isInfoEnabled()) {logger.info("Notify urls for subscribe url " + url + ", url size: " + urls.size());}// keep every provider's category.Map<String, List<URL>> result = new HashMap<>(); // 这里for (URL u : urls) {if (UrlUtils.isMatch(url, u)) {String category = u.getCategory(DEFAULT_CATEGORY);List<URL> categoryList = result.computeIfAbsent(category, k -> new ArrayList<>()); // 这里categoryList.add(u); // 这里}}if (result.size() == 0) {return;}Map<String, List<URL>> categoryNotified = notified.computeIfAbsent(url, u -> new ConcurrentHashMap<>());for (Map.Entry<String, List<URL>> entry : result.entrySet()) {String category = entry.getKey();List<URL> categoryList = entry.getValue();categoryNotified.put(category, categoryList);listener.notify(categoryList); // 这里// We will update our cache file after each notification.// When our Registry has a subscribe failure due to network jitter, we can return at least the existing cache URL.if (localCacheEnabled) {saveProperties(url);}}}
}
public class NacosRegistry extends FailbackRegistry {private void notifySubscriber(URL url, NotifyListener listener, Collection<Instance> instances) {List<Instance> enabledInstances = new LinkedList<>(instances);if (enabledInstances.size() > 0) {//  InstancesfilterEnabledInstances(enabledInstances);}List<URL> urls = toUrlWithEmpty(url, enabledInstances);NacosRegistry.this.notify(url, listener, urls); // 这里}String EMPTY_PROTOCOL = "empty";private List<URL> toUrlWithEmpty(URL consumerURL, Collection<Instance> instances) {List<URL> urls = buildURLs(consumerURL, instances);if (urls.size() == 0) { // 这里URL empty = URLBuilder.from(consumerURL).setProtocol(EMPTY_PROTOCOL).addParameter(CATEGORY_KEY, DEFAULT_CATEGORY).build();urls.add(empty);}return urls;}
}

当没有可用的服务时,instances是空的

 

当有可用的服务时,instances是不为空的

是怎么通知的

public class ServiceInfoHolder implements Closeable {public ServiceInfo processServiceInfo(ServiceInfo serviceInfo) {String serviceKey = serviceInfo.getKey();if (serviceKey == null) {return null;}ServiceInfo oldService = serviceInfoMap.get(serviceInfo.getKey());if (isEmptyOrErrorPush(serviceInfo)) {//empty or error push, just ignorereturn oldService;}serviceInfoMap.put(serviceInfo.getKey(), serviceInfo);boolean changed = isChangedServiceInfo(oldService, serviceInfo);if (StringUtils.isBlank(serviceInfo.getJsonFromServer())) {serviceInfo.setJsonFromServer(JacksonUtils.toJson(serviceInfo));}MetricsMonitor.getServiceInfoMapSizeMonitor().set(serviceInfoMap.size());if (changed) { // 这里NAMING_LOGGER.info("current ips:(" + serviceInfo.ipCount() + ") service: " + serviceInfo.getKey() + " -> "+ JacksonUtils.toJson(serviceInfo.getHosts()));NotifyCenter.publishEvent(new InstancesChangeEvent(serviceInfo.getName(), serviceInfo.getGroupName(),serviceInfo.getClusters(), serviceInfo.getHosts())); // 这里DiskCache.write(serviceInfo, cacheDir);}return serviceInfo;}
}public class DefaultPublisher extends Thread implements EventPublisher {private BlockingQueue<Event> queue;@Overridepublic void init(Class<? extends Event> type, int bufferSize) {setDaemon(true);setName("nacos.publisher-" + type.getName());this.eventType = type;this.queueMaxSize = bufferSize;this.queue = new ArrayBlockingQueue<>(bufferSize); // 这里start();}@Overridepublic boolean publish(Event event) {checkIsStart();boolean success = this.queue.offer(event); // 这里if (!success) {LOGGER.warn("Unable to plug in due to interruption, synchronize sending time, event : {}", event);receiveEvent(event);return true;}return true;}@Overridepublic void run() {openEventHandler();}void openEventHandler() {try {// This variable is defined to resolve the problem which message overstock in the queue.int waitTimes = 60;// To ensure that messages are not lost, enable EventHandler when// waiting for the first Subscriber to registerfor (; ; ) {if (shutdown || hasSubscriber() || waitTimes <= 0) {break;}ThreadUtils.sleep(1000L);waitTimes--;}for (; ; ) {if (shutdown) {break;}final Event event = queue.take(); // 这里receiveEvent(event);  // 这里UPDATER.compareAndSet(this, lastEventSequence, Math.max(lastEventSequence, event.sequence()));}} catch (Throwable ex) {LOGGER.error("Event listener exception : ", ex);}}void receiveEvent(Event event) {final long currentEventSequence = event.sequence();if (!hasSubscriber()) {LOGGER.warn("[NotifyCenter] the {} is lost, because there is no subscriber.");return;}// Notification single event listenerfor (Subscriber subscriber : subscribers) {// Whether to ignore expiration eventsif (subscriber.ignoreExpireEvent() && lastEventSequence > currentEventSequence) {LOGGER.debug("[NotifyCenter] the {} is unacceptable to this subscriber, because had expire",event.getClass());continue;}// Because unifying smartSubscriber and subscriber, so here need to think of compatibility.// Remove original judge part of codes.notifySubscriber(subscriber, event); // 这里}}@Overridepublic void notifySubscriber(final Subscriber subscriber, final Event event) {LOGGER.debug("[NotifyCenter] the {} will received by {}", event, subscriber);final Runnable job = () -> subscriber.onEvent(event);final Executor executor = subscriber.executor(); if (executor != null) {executor.execute(job); // 这里} else {try {job.run(); // 这里} catch (Throwable e) {LOGGER.error("Event callback exception: ", e);}}}
}public class InstancesChangeNotifier extends Subscriber<InstancesChangeEvent> {@Overridepublic void onEvent(InstancesChangeEvent event) {String key = ServiceInfo.getKey(NamingUtils.getGroupedName(event.getServiceName(), event.getGroupName()), event.getClusters());ConcurrentHashSet<EventListener> eventListeners = listenerMap.get(key);if (CollectionUtils.isEmpty(eventListeners)) {return;}for (final EventListener listener : eventListeners) {final com.alibaba.nacos.api.naming.listener.Event namingEvent = transferToNamingEvent(event);if (listener instanceof AbstractEventListener && ((AbstractEventListener) listener).getExecutor() != null) {((AbstractEventListener) listener).getExecutor().execute(() -> listener.onEvent(namingEvent)); // 这里} else {listener.onEvent(namingEvent); // 这里}}}
}public class NacosRegistry extends FailbackRegistry {@Overridepublic void onEvent(Event event) {if (event instanceof NamingEvent) {NamingEvent e = (NamingEvent) event;notifier.notify(e.getInstances()); // 这里}}
}public abstract class RegistryNotifier {public synchronized void notify(Object rawAddresses) {this.rawAddresses = rawAddresses;long notifyTime = System.currentTimeMillis();this.lastEventTime = notifyTime;long delta = (System.currentTimeMillis() - lastExecuteTime) - delayTime;// more than 10 calls && next execute time is in the futureboolean delay = shouldDelay.get() && delta < 0;if (delay) {scheduler.schedule(new NotificationTask(this, notifyTime), -delta, TimeUnit.MILLISECONDS); // 这里} else {// check if more than 10 callsif (!shouldDelay.get() && executeTime.incrementAndGet() > DEFAULT_DELAY_EXECUTE_TIMES) {shouldDelay.set(true);}scheduler.submit(new NotificationTask(this, notifyTime)); // 这里}}public static class NotificationTask implements Runnable {private final RegistryNotifier listener;private final long time;public NotificationTask(RegistryNotifier listener, long time) {this.listener = listener;this.time = time;}@Overridepublic void run() {try {if (this.time == listener.lastEventTime) {listener.doNotify(listener.rawAddresses); // 这里listener.lastExecuteTime = System.currentTimeMillis();synchronized (listener) {if (this.time == listener.lastEventTime) {listener.rawAddresses = null;}}}} catch (Throwable t) {logger.error("Error occurred when notify directory. ", t);}}}}
}public class NacosRegistry extends FailbackRegistry {private class RegistryChildListenerImpl implements EventListener {private RegistryNotifier notifier;public RegistryChildListenerImpl(String serviceName, URL consumerUrl, NotifyListener listener) {notifier = new RegistryNotifier(getUrl(), NacosRegistry.this.getDelay()) {@Overrideprotected void doNotify(Object rawAddresses) {List<Instance> instances = (List<Instance>) rawAddresses;if (isServiceNamesWithCompatibleMode(consumerUrl)) {/*** Get all instances with corresponding serviceNames to avoid instance overwrite and but with empty instance mentioned* in https://github.com/apache/dubbo/issues/5885 and https://github.com/apache/dubbo/issues/5899*/NacosInstanceManageUtil.initOrRefreshServiceInstanceList(serviceName, instances);instances = NacosInstanceManageUtil.getAllCorrespondingServiceInstanceList(serviceName);}NacosRegistry.this.notifySubscriber(consumerUrl, listener, instances); // 这里}};}
}

然后就调用了上面的👆🏻

什么时候添加监听器的?

public class NacosRegistry extends FailbackRegistry {private void subscribeEventListener(String serviceName, final URL url, final NotifyListener listener)throws NacosException {EventListener eventListener = new RegistryChildListenerImpl(serviceName, url, listener);  // 这里namingService.subscribe(serviceName,getUrl().getGroup(Constants.DEFAULT_GROUP),eventListener); // 这里}private void doSubscribe(final URL url, final NotifyListener listener, final Set<String> serviceNames) {try {if (isServiceNamesWithCompatibleMode(url)) {List<Instance> allCorrespondingInstanceList = Lists.newArrayList();/*** Get all instances with serviceNames to avoid instance overwrite and but with empty instance mentioned* in https://github.com/apache/dubbo/issues/5885 and https://github.com/apache/dubbo/issues/5899** namingService.getAllInstances with {@link org.apache.dubbo.registry.support.AbstractRegistry#registryUrl}* default {@link DEFAULT_GROUP}** in https://github.com/apache/dubbo/issues/5978*/for (String serviceName : serviceNames) {List<Instance> instances = namingService.getAllInstances(serviceName,getUrl().getGroup(Constants.DEFAULT_GROUP));NacosInstanceManageUtil.initOrRefreshServiceInstanceList(serviceName, instances);allCorrespondingInstanceList.addAll(instances);}notifySubscriber(url, listener, allCorrespondingInstanceList); for (String serviceName : serviceNames) {subscribeEventListener(serviceName, url, listener); // 这里}} else {for (String serviceName : serviceNames) {List<Instance> instances = new LinkedList<>();instances.addAll(namingService.getAllInstances(serviceName, getUrl().getGroup(Constants.DEFAULT_GROUP)));String serviceInterface = serviceName;String[] segments = serviceName.split(SERVICE_NAME_SEPARATOR, -1);if (segments.length == 4) {serviceInterface = segments[SERVICE_INTERFACE_INDEX];}URL subscriberURL = url.setPath(serviceInterface).addParameters(INTERFACE_KEY, serviceInterface,CHECK_KEY, String.valueOf(false));notifySubscriber(subscriberURL, listener, instances);subscribeEventListener(serviceName, subscriberURL, listener);}}} catch (Throwable cause) {throw new RpcException("Failed to subscribe " + url + " to nacos " + getUrl() + ", cause: " + cause.getMessage(), cause);}}
}

org.apache.dubbo.rpc.RpcException: Directory already destroyed

public abstract class AbstractDirectory<T> implements Directory<T> {@Overridepublic List<Invoker<T>> list(Invocation invocation) throws RpcException {if (destroyed) {throw new RpcException("Directory already destroyed .url: " + getUrl());}return doList(invocation);}@Overridepublic void destroy() {destroyed = true; // 这里}
}
public class ReferenceConfig<T> extends ReferenceConfigBase<T> {private void checkInvokerAvailable() throws IllegalStateException {if (shouldCheck() && !invoker.isAvailable()) {invoker.destroy(); // 这里throw new IllegalStateException("Should has at least one way to know which services this interface belongs to," +" subscription url: " + invoker.getUrl());}}protected synchronized void init() {// ......checkInvokerAvailable(); // 这里}}
public abstract class ReferenceConfigBase<T> extends AbstractReferenceConfig {public boolean shouldCheck() {checkDefault();Boolean shouldCheck = isCheck(); // 这里if (shouldCheck == null && getConsumer() != null) {shouldCheck = getConsumer().isCheck(); }if (shouldCheck == null) {// default true // 这里shouldCheck = true;}return shouldCheck;}
}
public class RegistryDirectory<T> extends DynamicDirectory<T> {@Overridepublic boolean isAvailable() {if (isDestroyed() || this.forbidden) { // 这里return false;}Map<URL, Invoker<T>> localUrlInvokerMap = urlInvokerMap; // 这里return CollectionUtils.isNotEmptyMap(localUrlInvokerMap)&& localUrlInvokerMap.values().stream().anyMatch(Invoker::isAvailable);}
}

如果没有设置check字段,那么就会在启动的时 候检查提供方是否可用,如果不可用,就销毁了。

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

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

相关文章

使用dockerfile手动构建JDK11镜像运行容器并校验

Docker官方维护镜像的公共仓库网站 Docker Hub 国内无法访问了&#xff0c;大部分镜像无法下载&#xff0c;准备逐步构建自己的镜像库。【转载aliyun官方-容器镜像服务 ACR】Docker常见问题 阿里云容器镜像服务ACR&#xff08;Alibaba Cloud Container Registry&#xff09;是面…

内网穿透-外远程连接中的RabbitMQ服务

文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 RabbitMQ是一个在 AMQP(高级消息队列协议)基…

Linux:shell脚本:基础使用(4)《正则表达式-grep工具》

正则表达式定义&#xff1a; 使用单个字符串来描述&#xff0c;匹配一系列符合某个句法规则的字符串 正则表达式的组成&#xff1a; 普通字符串: 大小写字母&#xff0c;数字&#xff0c;标点符号及一些其他符号 元字符&#xff1a;在正则表达式中具有特殊意义的专用字符 正则表…

蓝桥杯嵌入式省一教程:(三)按键扫描与定时器中断

在第一讲中曾经提到&#xff0c;GPIO有输入输出两种模式。在点亮LED时&#xff0c;我们已经使用了GPIO输出模式&#xff0c;在按键识别中&#xff0c;我们将要使用GPIO输入模式。首先来看看按键的电路原理图&#xff08;下图在选手资源数据包——CT117E-M4产品手册中&#xff0…

高等数学教材重难点题型总结(三)微分中值定理和导数的应用

第三章&#xff0c;微分中值定理的证明题等&#xff0c;非常重要&#xff0c;需要牢牢掌握 1.证明中值定理对某函数在给定区间上的正确性 2.与中值定理有关的证明题 3.微分中值定理应用于求证不等式 4.洛必达法则求极限 5.洛必达的经典错误反例 6.按某项实现多项式幂展开 7.求带…

以 Java NIO 的角度理解 Netty

文章目录 前言Java NIO 工作原理Selector 的创建ServerSocketChannel 的创建ServerSocketChannel 注册 Selector对事件的处理总结 前言 上篇文章《Netty 入门指南》主要涵盖了 Netty 的入门知识&#xff0c;包括 Netty 的发展历程、核心功能与组件&#xff0c;并且通过实例演示…

rabbitmq的发布确认

生产者将信道设置成 confirm 模式&#xff0c;一旦信道进入 confirm 模式&#xff0c; 所有在该信道上面发布的 消息都将会被指派一个唯一的 ID (从 1 开始)&#xff0c;一旦消息被投递到所有匹配的队列之后&#xff0c;broker 就会发送一个确认给生产者(包含消息的唯一 ID)&…

AI巨浪下,数据技术如何驱动智能未来?

引言 数据技术是大数据时代的核心驱动力&#xff0c;也是推动各行各业数字化转型和智能化升级的关键因素。随着云计算、人工智能、区块链等新兴技术的不断发展和融合&#xff0c;数据技术也呈现出多模态、混合处理、自动化管理等新的趋势和特点。 8 月 19 日&#xff08;周六&…

【宝藏系列】嵌入式 C 语言代码优化技巧【超详细版】

【宝藏系列】嵌入式 C 语言代码优化技巧【超详细版】 文章目录 【宝藏系列】嵌入式 C 语言代码优化技巧【超详细版】前言整形数除法和取余数合并除法和取余数通过2的幂次进行除法和取余数取模的一种替代方法使用数组下标全局变量使用别名变量的生命周期分割变量类型局部变量指针…

STM32 F103C8T6学习笔记3:串口配置—串口收发—自定义Printf函数

今日学习使用STM32 C8T6的串口&#xff0c;我们在经过学习笔记2的总结归纳可知&#xff0c;STM32 C8T6最小系统板上有三路串口&#xff0c;如下图&#xff1a; 今日我们就着手学习如何配置开通这些串口进行收发&#xff0c;这里不讲串口通信概念与基础&#xff0c;可以自行网上…

一文读懂HTML

文章目录 HTML的历史HTML的作用HTML的基本语言 HTML的历史 HTML&#xff08;HyperText Markup Language&#xff09;的历史可以追溯到20世纪90年代早期&#xff0c;它是互联网发展的重要里程碑之一。以下是HTML的历史概述&#xff1a; 早期阶段&#xff08;1980年代末 - 1990年…

FLatten Transformer 简化版Transformer

今天在找论文时&#xff0c;看到一篇比较新奇的论文&#xff0c;在这里跟大家分享一下&#xff0c;希望可以给一些人提供一些思路。虽然现在Transformer 比较火&#xff0c;在分割上面也应用的比较多&#xff0c;但是我一直不喜欢用&#xff0c;其中一个原因是结构太复杂了&…

C++:模拟实现list及迭代器类模板优化方法

文章目录 迭代器模拟实现 本篇模拟实现简单的list和一些其他注意的点 迭代器 如下所示是利用拷贝构造将一个链表中的数据挪动到另外一个链表中&#xff0c;构造两个相同的链表 list(const list<T>& lt) {emptyinit();for (auto e : lt){push_back(e);} }void test_…

运动路径规划,ROS发布期望运动轨迹

目录 一、Python实现&#xff08;推荐方法&#xff09; 1.1代码cubic_spline_path.py 1.2使用方法 二、C实现 参考博客 想让机器人/智能车无人驾驶&#xff0c;要有期望路径&#xff0c;最简单的是一条直线&#xff0c;或者是一条光滑曲线。 生成路径的方法有两种&#xf…

【网络编程(二)】NIO快速入门

NIO Java NIO 三大核心组件 Buffer&#xff08;缓冲区&#xff09;&#xff1a;每个客户端连接都会对应一个Buffer&#xff0c;读写数据通过缓冲区读写。Channel&#xff08;通道&#xff09;&#xff1a;每个channel用于连接Buffer和Selector&#xff0c;通道可以进行双向读…

Redis数据库的可视化工具AnotherRedisDesktopManager使用+抖音直播小玩法实践

一、它是什么 Another Redis DeskTop Manager 是一个开源项目&#xff0c;提供了以可视化的方式管理 Redis 的功能&#xff0c;可供免费下载安装&#xff0c;也可以在此基础上进行二次开发&#xff0c;主要特点有&#xff1a; 支持 Windows 平台和 MacOS 平台 支持查询 Key、…

QT中的按钮控件Buttons介绍

目录 Buttons 按钮控件 1、常用属性介绍 2、按钮介绍 2.1QPushButton 普通按钮 2.2QtoolButton 工具按钮 2.3Radio Button单选按钮 2.4CheckButton复选按钮 2.5Commam Link Button命令链接按钮 2.6Dialog Button Box命令链接按钮 Buttons 按钮控件 在Qt里&#xff0c;…

Viobot开机指南

0.前言 本篇旨在让每个拿到Viobot设备的用户都能够第一时间测试它的效果&#xff0c;以及将设备配置到自己的环境下面。 1.上电 首先&#xff0c;我们先要把设备接上电源线和网线&#xff0c;最简单的方式就是网线直连电脑。 电源选用12V1.5A设备自带的电源即可。 2.配置网…

深入学习前端开发,掌握HTML、CSS、JavaScript等技术

课程链接&#xff1a; 链接: https://pan.baidu.com/s/1WECwJ4T8UQfs2FyjUMbxig?pwdi654 提取码: i654 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 --来自百度网盘超级会员v4的分享 课程介绍&#xff1a; 第1周&#xff1a;HTML5基础语法与标签 &#x1f…

web集群学习:搭建 LNMP应用环境

目录 LNMP的介绍&#xff1a; LNMP组合工作流程&#xff1a; FastCGI介绍&#xff1a; 1、什么是 CGI 2、什么是 FastCGI 配置LNMP 1、部署LNMP环境 2、配置LNMP环境 LNMP的介绍&#xff1a; 随着 Nginx Web 服务的逐渐流行&#xff0c;又岀现了新的 Web 服务环境组合—…