Spring Cloud Sleuth系列(1) — Sleuth环境搭建以及Feign整合调用分析

news/2024/4/20 10:26:06/文章来源:https://blog.csdn.net/weixin_46053046/article/details/127411474

文章目录

  • 前言
  • 一、基础环境搭建
    • 1、项目环境搭建
    • 2、zipkin server启动
    • 3、基于Feign进行服务调用
  • 二、Sleuth + Feign调用源码分析
    • 1、调用链分析
    • 2、Sleuth针对Feign进行的改造
  • 总结

前言

该篇文章,主要介绍Spring Cloud Sleuth + Zipkin基础环境搭建,以及基于源码侧分析,使用Feign进行调用服务时,Sleuth如何做到无感收集Span信息。

一、基础环境搭建

1、项目环境搭建

为避免在pom.xml中,直接添加sleuth、zipkin依赖,出现版本冲突等问题,而导致项目启动失败,这里,使用aliyun脚手架,初始化该环境。
在这里插入图片描述
这里,使用分层架构中的web基础示例模式,搭建环境,项目结构如下所示:
在这里插入图片描述
将api以及web两个模块,添加相关启动类等代码,使其作为两个启动服务。其中bootstrap.properties用于配置nacos相关信息,用于服务注册和发现。

spring.cloud.nacos.config.server-addr=localhost:8848
spring.cloud.nacos.config.username=nacos
spring.cloud.nacos.config.password=nacos
spring.cloud.nacos.config.namespace=d60c4d2a-7ea0-4a8b-9eea-689a30bc5aa5spring.cloud.nacos.discovery.server-addr=${spring.cloud.nacos.config.server-addr}
spring.cloud.nacos.discovery.user-name=${spring.cloud.nacos.config.username}
spring.cloud.nacos.discovery.password=${spring.cloud.nacos.config.password}
spring.cloud.nacos.discovery.namespace=${spring.cloud.nacos.config.namespace}

application.properties,配置zipkin服务信息(两个服务配置信息类似)。

spring.application.name=distribute-api
server.port=10001spring.zipkin.baseUrl=http://127.0.0.1:9411
debug=true

2、zipkin server启动

zipkin官网,提供多种方式,介绍zipkin server启动。现按照“Running from Source”,采用源码编码启动方式,启动zipkin server。

# get the latest source
git clone https://github.com/openzipkin/zipkin
cd zipkin
# Build the server and also make its dependencies
./mvnw -DskipTests --also-make -pl zipkin-server clean install
# Run the server
java -jar ./zipkin-server/target/zipkin-server-*exec.jar

在这里插入图片描述

3、基于Feign进行服务调用

api模块中,通过Feign请求web模块服务。

// 配置Feign
@Configuration
@EnableFeignClients(basePackages = "com.quelongjiang.**.feigins")
public class DistributeFeignConfig {
}// 用于调用web模块请求
@FeignClient(value = "distribute-web", path = "quelongjiang/webController")
public interface WebOperatorFeigin {@GetMapping("info")String info();
}// 在api模块,编写请求,并通过Feign调用web模块请求
@Slf4j
@RestController
@RequestMapping("quelongjiang/apiRequestController")
public class ApiRequestController {@Value("${spring.application.name}")private String applicationName;@Autowiredprivate WebOperatorFeigin webFeigin;@GetMapping("info")public String info() {this.webFeigin.info();log.info("Web Request Response is {}", this.webFeigin.info());return "This is " + applicationName + " request.";}@PostMapping("info")public Map<String, Object> infoPost() {Map<String, Object> response = new HashMap<>();response.put("MESSAGE", "This is " + applicationName + " request.");return response;}
}

分别启动web和api两个服务,并请求api模块请求,在zipkin server 界面,可看到上述截图内容。

二、Sleuth + Feign调用源码分析

1、调用链分析

ApiRequestController.info中关于WebOperatorFeigin.info方法内部调用链,梳理总结如下

WebOperatorFeigin.info -> ReflectiveFeign.FeignInvocationHandler.invoke -> SynchronousMethodHandler.invoke -> client.execute (TraceLoadBalancerFeignClient) -> LoadBalancerFeignClient.execute -> AbstractLoadBalancerAwareClient.executeWithLoadBalancer -> LazyTracingFeignClient.execute -> TracingFeignClient.execute

针对上述内容,进行如下解释

1、基于动态代理方式,创建WebOperatorFeigin接口实现类,内部处理逻辑对应FeignInvocationHandler的invoke方法。
2、FeignInvocationHandler.invoke方法,通过method确定该方法对应的MethodHandler处理类,此处,对应于SynchronousMethodHandler类。
3、SynchronousMethodHandler.invoke内部,通过client.execute完成请求处理,client属性为Client接口实现类,此处,对应于TraceLoadBalancerFeignClient实现类。该实现类为LoadBalancerFeignClient子类。
4、LoadBalancerFeignClient.execute,通过一系列参数转换,最终通过delegate属性,完成execute,此处delegate对应于TracingFeignClient。

相关代码展示如下

// TraceLoadBalancerFeignClient类代码
@Override
public Response execute(Request request, Request.Options options) throws IOException {if (log.isDebugEnabled()) {log.debug("Before send");}Response response = null;// 创建SpanSpan fallbackSpan = tracer().nextSpan().start();try {if (delegateIsALoadBalancer()) {response = getDelegate().execute(request, options);}else {// TraceLoadBalancerFeignClient继承 LoadBalancerFeignClient,此处,使用父类execute方法,进行请求调用。response = super.execute(request, options);}if (log.isDebugEnabled()) {log.debug("After receive");}return response;}catch (Exception e) {// 省略部分代码}finally {fallbackSpan.abandon();}
}// LoadBalancerFeignClient
@Override
public Response execute(Request request, Request.Options options) throws IOException {try {URI asUri = URI.create(request.url());String clientName = asUri.getHost();URI uriWithoutHost = cleanUrl(request.url(), clientName);FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(this.delegate, request, uriWithoutHost);IClientConfig requestConfig = getClientConfig(options, clientName);// lbClient,基于CachingSpringLoadBalancerFactory,借助于clientName,创建FeignLoadBalancer。// executeWithLoadBalancer在AbstractLoadBalancerAwareClient定义,具体的execute方法,在实现类(FeignLoadBalancer)定义return lbClient(clientName).executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();}catch (ClientException e) {// 省略部分代码}
}// FeignLoadBalancer
@Override
public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride)throws IOException {Request.Options options;if (configOverride != null) {RibbonProperties override = RibbonProperties.from(configOverride);options = new Request.Options(override.connectTimeout(this.connectTimeout),override.readTimeout(this.readTimeout));}else {options = new Request.Options(this.connectTimeout, this.readTimeout);}// 该request.client对应于Client实现类。// request传参,于LoadBalancerFeignClient.execute方法中指定,其client方法,对应于该类的delegate属性。Response response = request.client().execute(request.toRequest(), options);return new RibbonResponse(request.getUri(), response);
}

2、Sleuth针对Feign进行的改造

通过上述分析,对于整体处理流程,有了一个大概的了解。接下来,通过解答3个问题,完成Sleuth对Feign调用改造分析。

1)SynchronousMethodHandler中client属性,如何被替换成TraceLoadBalancerFeignClient?
2)LoadBalancerFeignClient.execute,delegate属性,如何最终传递到LazyTracingFeignClient.execute?
3)如何将TracingFeignClient作为delegate属性,传递进LoadBalancerFeignClient?

在解答上述3个问题前,先介绍另外一个类,FeignContextBeanPostProcessor,正是这个类,完成Feign改头换面。

final class FeignContextBeanPostProcessor implements BeanPostProcessor {private final BeanFactory beanFactory;// 省略部分代码@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName)throws BeansException {// 将FeignContext类型的Bean,转换成TraceFeignContext。// Sleuth对Feign内部关键Bean的替换,是通过TraceFeignObjectWrapper完成的。if (bean instanceof FeignContext && !(bean instanceof TraceFeignContext)) {return new TraceFeignContext(traceFeignObjectWrapper(), (FeignContext) bean);}return bean;}private TraceFeignObjectWrapper traceFeignObjectWrapper() {return new TraceFeignObjectWrapper(this.beanFactory);}
}

FeignContextBeanPostProcessor,将FeignContext类型的bean,替换成TraceFeignContext。两者为继承关系,代码差异体现在getInstance方法。既TraceFeignContext的getInstance方法,都会经过TraceFeignObjectWrapper.wrap修饰。

class TraceFeignContext extends FeignContext {private final TraceFeignObjectWrapper traceFeignObjectWrapper;private final FeignContext delegate;TraceFeignContext(TraceFeignObjectWrapper traceFeignObjectWrapper,FeignContext delegate) {this.traceFeignObjectWrapper = traceFeignObjectWrapper;this.delegate = delegate;}@Override@SuppressWarnings("unchecked")public <T> T getInstance(String name, Class<T> type) {T object = this.delegate.getInstance(name, type);if (object != null) {// 将FeignContext .getInstance方法获取的对象,使用TraceFeignObjectWrapper.wrap修饰一遍。// 也就是在这里,Sleuth将Feign原相关处理类,替换成Sleuth自己的亲信。return (T) this.traceFeignObjectWrapper.wrap(object);}return null;}// 省略部分代码
}

现在来分析TraceFeignObjectWrapper.wrap方法。

// TraceFeignObjectWrapper
Object wrap(Object bean) {// 针对Client类型的对象,进行大洗牌,替换成Sleuth自己的。if (bean instanceof Client && !(bean instanceof TracingFeignClient)) {// 将LoadBalancerFeignClient,替换成TraceLoadBalancerFeignClientif (ribbonPresent && bean instanceof LoadBalancerFeignClient&& !(bean instanceof TraceLoadBalancerFeignClient)) {return instrumentedFeignRibbonClient(bean);}if (ribbonPresent && bean instanceof TraceLoadBalancerFeignClient) {return bean;}// 将FeignBlockingLoadBalancerClient,替换成TraceFeignBlockingLoadBalancerClientif (loadBalancerPresent && bean instanceof FeignBlockingLoadBalancerClient&& !(bean instanceof TraceFeignBlockingLoadBalancerClient)) {return instrumentedFeignLoadBalancerClient(bean);}if (loadBalancerPresent&& bean instanceof RetryableFeignBlockingLoadBalancerClient&& !(bean instanceof TraceRetryableFeignBlockingLoadBalancerClient)) {return instrumentedRetryableFeignLoadBalancerClient(bean);}if (ribbonPresent && bean instanceof TraceFeignBlockingLoadBalancerClient) {return bean;}return new LazyTracingFeignClient(this.beanFactory, (Client) bean);}return bean;
}

现在开始解答上述三个问题。

1、SynchronousMethodHandler中client属性,如何被替换成TraceLoadBalancerFeignClient?

回答这个问题前,需先了解Feign代理类,是如何创建的,可参考FeignClient代理类创建过程分析 博文。此处,只列出相关代码。
FeignClientFactoryBean创建Feign代理类时,首先通过Spring上下文环境获取Client对象(此时为TraceLoadBalancerFeignClient),然后,通过getObject获取Feign代理对象。
getObject方法内部,最后通过getTarget方法,创建代理类。其中client属性,设置进Builder,后续在build方法中,用以创建Factory,通过调用create方法,创建SynchronousMethodHandler传入,client也就是这个时候,进驻到SynchronousMethodHandler。

// FeignClientFactoryBean
<T> T getTarget() {FeignContext context = applicationContext.getBean(FeignContext.class);Feign.Builder builder = feign(context);if (!StringUtils.hasText(url)) {if (!name.startsWith("http")) {url = "http://" + name;}else {url = name;}url += cleanPath();return (T) loadBalance(builder, context,new HardCodedTarget<>(type, name, url));}if (StringUtils.hasText(url) && !url.startsWith("http")) {url = "http://" + url;}String url = this.url + cleanPath();// 通过Spring上下文,获取Client,此处LoadBalancerFeignClient Bean,经由TraceFeignObjectWrapper,已替换成TraceLoadBalancerFeignClient Bean。Client client = getOptional(context, Client.class);if (client != null) {if (client instanceof LoadBalancerFeignClient) {// not load balancing because we have a url,// but ribbon is on the classpath, so unwrapclient = ((LoadBalancerFeignClient) client).getDelegate();}if (client instanceof FeignBlockingLoadBalancerClient) {// not load balancing because we have a url,// but Spring Cloud LoadBalancer is on the classpath, so unwrapclient = ((FeignBlockingLoadBalancerClient) client).getDelegate();}builder.client(client);}Targeter targeter = get(context, Targeter.class);// HystrixTargeter实现类,内部,通过builder.target方法,创建代理类。return (T) targeter.target(this, builder, context,new HardCodedTarget<>(type, name, url));
}// Feign.Builder类
public Feign build() {Client client = (Client)Capability.enrich(this.client, this.capabilities);Retryer retryer = (Retryer)Capability.enrich(this.retryer, this.capabilities);List<RequestInterceptor> requestInterceptors = (List)this.requestInterceptors.stream().map((ri) -> {return (RequestInterceptor)Capability.enrich(ri, this.capabilities);}).collect(Collectors.toList());Logger logger = (Logger)Capability.enrich(this.logger, this.capabilities);Contract contract = (Contract)Capability.enrich(this.contract, this.capabilities);Options options = (Options)Capability.enrich(this.options, this.capabilities);Encoder encoder = (Encoder)Capability.enrich(this.encoder, this.capabilities);Decoder decoder = (Decoder)Capability.enrich(this.decoder, this.capabilities);InvocationHandlerFactory invocationHandlerFactory = (InvocationHandlerFactory)Capability.enrich(this.invocationHandlerFactory, this.capabilities);QueryMapEncoder queryMapEncoder = (QueryMapEncoder)Capability.enrich(this.queryMapEncoder, this.capabilities);// 将Client对象,传递进Factory ,并用以构建ParseHandlersByName 对象。// 在ReflectiveFeign内部,通过ParseHandlersByName.apply方法处,通过factory.create方法,创建SynchronousMethodHandler对象。Factory synchronousMethodHandlerFactory = new Factory(client, retryer, requestInterceptors, logger, this.logLevel, this.decode404, this.closeAfterDecode, this.propagationPolicy, this.forceDecoding);ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder, this.errorDecoder, synchronousMethodHandlerFactory);return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}

2、LoadBalancerFeignClient.execute,delegate属性,如何到达LazyTracingFeignClient.execute?

LoadBalancerFeignClient.execute方法,使用delegate属性,构造RibbonRequest对象,该对象用于请求参数,传递进FeignLoadBalancer的execute方法。此时,delegate,经过wrap修饰后,变成LazyTracingFeignClient。

// LoadBalancerFeignClient
@Override
public Response execute(Request request, Request.Options options) throws IOException {try {URI asUri = URI.create(request.url());String clientName = asUri.getHost();URI uriWithoutHost = cleanUrl(request.url(), clientName);FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(this.delegate, request, uriWithoutHost);IClientConfig requestConfig = getClientConfig(options, clientName);// lbClient方法,创建FeignLoadBalancer对象,executeWithLoadBalancer方法在AbstractLoadBalancerAwareClient定义,为FeignLoadBalancer父类。// ribbonRequest对应于FeignLoadBalancer.RibbonRequest,其构造方法处,已保存FeignLoadBalancer.delegate属性。return lbClient(clientName).executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();}catch (ClientException e) {IOException io = findIOException(e);if (io != null) {throw io;}throw new RuntimeException(e);}
}// FeignLoadBalancer
@Override
public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride)throws IOException {Request.Options options;if (configOverride != null) {RibbonProperties override = RibbonProperties.from(configOverride);options = new Request.Options(override.connectTimeout(this.connectTimeout),override.readTimeout(this.readTimeout));}else {options = new Request.Options(this.connectTimeout, this.readTimeout);}// 通过请求参数RibbonRequest,获取client对象,此对象来源于LoadBalancerFeignClient.execute方法中构造的RibbonRequest。Response response = request.client().execute(request.toRequest(), options);return new RibbonResponse(request.getUri(), response);
}

3、如何将TracingFeignClient作为delegate属性,传递进LoadBalancerFeignClient?

a、TraceLoadBalancerFeignClient继承LoadBalancerFeignClient,内部增加BeanFactory属性。
b、基于Bean Factory,获取Tracer、HttpTracing、TracingFeignClient属性。
c、通过TraceFeignObjectWrapper.instrumentedFeignRibbonClient,将Client替换成LazyTracingFeignClient对象。
d、将LazyTracingFeignClient,设置进TraceLoadBalancerFeignClient.delegate属性。

总结

Sleuth借助于TraceFeignObjectWrapper.wrap方法,将原Feign工作所使用的Client转换成Sleuth自己的Client,并在这些Client内部,完成Span对象的创建。

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

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

相关文章

文华财经多个非常实用的期货指标公式,文华财经支撑压力自动画线公式

期货指标公式是通过数学逻辑角度计算而来&#xff0c;仅是期货分析环节中的一个辅助工具。期货市场具有不确定性和不可预测性的&#xff0c;请正常对待和使用指标公式! 期货指标公式信号本身就有滞后性&#xff0c;周期越大&#xff0c;滞后性越久。指标公式不是100%稳赚的工具…

畅享云原生超融合技术成果

作者&#xff1a;Vishal Ghariwala&#xff0c;SUSE 亚太及大中华区 CTO 超融合是服务器虚拟化和 VSAN 存储的必然发展结果。通过将存储、计算和网络这三大要素相集成&#xff0c;理论上数据中心对基础设施的控制能力可以无限扩展。这与超大规模运营商的发展目标高度契合&#…

电影主题HTM5网页设计作业成品——爱影评在线电影(10页面)使用dreamweaver制作采用DIV+CSS进行布局

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 文章目录一、网页介绍一…

【AGC035E】Develop(图论,DP)

对于某个集合 S⊆{1,⋯,n}S\subseteq\{1,\cdots,n\}S⊆{1,⋯,n}&#xff0c;考虑能不能删去 SSS。 对于任意 x∈Sx\in Sx∈S&#xff0c;连边 x→x−2x\to x-2x→x−2&#xff08;如果 x−2∈Sx-2\in Sx−2∈S&#xff09;及 x→xkx\to xkx→xk&#xff08;如果 xk∈Sxk\in Sx…

Ajax的概念及jQuery中的Ajax的3种方法,模仿jQuery封装自己的Ajax函数

目录一、网页中如何请求数据资源的请求方式二、Ajax1、什么是Ajax2、Ajax的特点3、Ajax工作原理4、同步与异步的区别三、jQuery中的Ajax1、$.get()函数2、$.post()函数3、$.ajax()函数四、模仿jQuery封装自己的Ajax函数实现效果1、定义options参数选项2、定义resoveData()函数处…

Clustering and Projected Clustering with Adaptive Neighbors

摘要 在本文中&#xff0c;提出了一种新的聚类模型来同时学习数据相似矩阵和聚类结构。新模型通过基于局部距离为每个数据点分配自适应和最优邻居来学习数据相似性矩阵。同时&#xff0c;对数据相似性矩阵的拉普拉斯矩阵施加新的秩约束&#xff0c;使得得到的相似性矩阵中的连…

特殊的线性规划:目标函数中的变量数目少于约束中的变量数目

如下&#xff0c;目标函数为min(x1)&#xff0c;该函数中只存在一个变量x1&#xff0c;但是约束中存在x2变量&#xff0c;线性规划还能求解吗&#xff1f;如下&#xff0c;目标函数为min (x_1)&#xff0c;该函数中只存在一个变量x_1&#xff0c;但是约束中存在x_2变量&#xf…

ES Elasticsearch

ES 本章知识点 三 ES简介 3.1 数据分类 我们生活中的数据总体分为三种&#xff1a;结构化数据&#xff0c;非结构化数据&#xff0c;半结构化数据结构化数据&#xff1a;指具有固定格式或有限长度的数据&#xff0c;如数据库&#xff0c;元数据等。 非结构化数据&#xff1…

【百日刷题计划 第十一天】——熟悉函数,递归及递推 函数,递归及递推基础题

文章目录&#x1f4a5;前言&#x1f609;解题报告&#x1f4a5;[NOIP2001 普及组] 数的计算&#x1f914;一、思路:&#x1f60e;二、源码&#xff1a;&#x1f62e;三、代码分析&#xff1a;&#x1f917; 鸡汤来咯&#xff1a;&#x1f4a5;前言 ☀️大家好☀️&#xff0c;我…

2018年美亚杯电子数据取证大赛-团体赛

&#x1f60b;大家好&#xff0c;我是YAy_17&#xff0c;是一枚爱好网安的小白&#xff0c;正在自学ing。 本人水平有限&#xff0c;欢迎各位大佬指点&#xff0c;一起学习&#x1f497;&#xff0c;一起进步⭐️。 ⭐️此后如竟没有炬火&#xff0c;我便是唯一的光。⭐️ 目…

RISC-V学习基础(五)

RISC-V汇编语言 C程序翻译成为可以在计算机上执行的机器语言程序的四个经典步骤。 函数调用规范&#xff08;Calling convention&#xff09; 函数调用过程通常分为6个阶段&#xff1a; 将参数存储到函数能够访问的位置。跳转到函数开始位置&#xff08;使用RV32I的jal指令…

考研图论算法

图论——txf 倘若考研需要像写算法题目那样&#xff0c;写出图论的代码&#xff0c;那无疑图论是最难级别的。 -----Williams Tian 1. 重点表述 ①线形表可以空表&#xff0c;树可以空树&#xff0c;但是图不能一个顶点也没有&#xff08;允许一条边也没有&#xff09;. ②…

ETC-4 week 3th

ETC-4 week 3th 出奇至胜 read They are only charged for the amount of power they consume on rainy days.They needn’t pay a single cent for their power consumption(消耗能量) on sunny days.(13 june) consume v 消耗 耗尽 吃光 喝光 沉溺 浪费LOL consumes(消耗…

安装docker,打包jar包镜像文件,输出tar压缩包

打包 jar 步骤在文章最后&#xff0c;不需要安装的请直接跳到文末查看 一键安装命令&#xff1a; curl -sSL https://get.daocloud.io/docker | sh设置开机自启并启动docker systemctl enable docker.service启动docker systemctl start docker查看docker状态 systemctl s…

创新洞见|2023年B2B业务为何必须采用PLG增长策略

随着采用PLG模式的大型企业数量不断增加&#xff0c;91%的公司计划在2022年增加对PLG战略的投资&#xff0c;市场上已经验证了PLG公司的表现优于其竞争对手&#xff0c;规模增长更快&#xff0c;并拥有更高的企业价值&#xff08;EV&#xff09;。PLG象征着购买决策者的转变&am…

【附源码】计算机毕业设计SSM数据时代下的疫情管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Java多线程之Thread和Runnable关于共享资源的对比

背景 Thread和Runnable关于共享资源的对比&#xff0c;网上看到很多不正确的结论如下&#xff1a; Thread类创建多线程&#xff0c;无法保证多个线程对共享资源的正确操作&#xff0c;而Runnable接口可以保证多个线程对共享资源的正确访问。 得到这个结论的原因如下&#xff1…

【Pytorch】learning notes

文章目录【torch.xxx】torch.addmm() / torch.addmm_()torch.clamp() / torch.clamp_()torch.eq() / torch.ne()torch.manual_seed()torch.unique()torch.save() / torch.load()torch.view() / torch.permute() / torch. transpose() / torch.reshape()【torch.cuda.xxx】torch…

可以替代911s5的这几款产品还有跨境人士不知道吗?

不久前跨境电商用户都收到的坏消息无疑就是&#xff1a;911s5正式宣布停止运营并永久关闭。对于911s5&#xff0c;相信几乎所有的跨境电商用户都知道&#xff0c;因为其低廉的价格一直很受欢迎。所以一时间大家纷纷寻找911s5的替代品&#xff0c;但不是那么容易找的。今天这篇文…

投资组合图形化:EAP.util.plot

实证资产定价&#xff08;Empirical asset pricing&#xff09;已经发布于Github和Pypi. 包的具体用法(Documentation)博主将会陆续在CSDN中详细介绍&#xff0c;也可以通过Pypi直接查看。 Pypi: pip install --upgrade EAP HomePage&#xff1a; EAP a catchy description …