范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

一些可以显著提高大型Java项目启动速度的尝试

  我们线上的业务 jar 包基本上普遍比较庞大,动不动一个 jar 包上百 M,启动时间在分钟级,拖慢了我们在故障时快速扩容的响应。于是做了一些分析,看看 Java 程序启动慢到底慢在哪里,如何去优化,目前的效果是大部分大型应用启动时间可以缩短 30%~50%
  主要有下面这些内容修改 async-profiler 源码,只抓取启动阶段 main 线程的 wall 时间火焰图( )重新实现 JarIndex( )结合 JarIndex 重新自定义类加载器,启动提速 30%+( )SpringBean 加载耗时 timeline 可视化分析( )SpringBean 的可视化依赖分析( )基于依赖拓扑的 SpringBean 的异步加载( )无观测不优化
  秉承着无观测不优化的想法,首先我们要知道启动慢到底慢在了哪里。我之前分享过很多次关于火焰图的使用,结果很多人遇到问题就开始考虑火焰图,但是一个启动慢其实是一个时序问题,不是一个 hot CPU 热点问题。很多时候慢,不一定是 cpu 占用过高,很有可能是等锁、等 IO 或者傻傻的 sleep。
  在 Linux 中有一个杀手级的工具 bootchart 来分析 linux 内核启动的问题,它把启动过程中所有的 IO、CPU 占用情况都做了详细的划分,我们可以很清楚地看到各个时间段,时间耗在了哪里,基于这个 chart,你就可以看看哪些过程可以延后处理、异步处理等。
  在 Java 中,暂时没有类似的工具,但是又想知道时间到底耗在了哪里要怎么做呢,至少大概知道耗在了什么地方。在生成热点调用火焰图的时候,我们通过 arthas 的几个简单的命令就可以生成,它底层用的是 async-profiler 这个开源项目,它的作者 apangin 做过一系列关于 jvm profiling 相关的分享,感兴趣的同学可以去看看。async-profiler 底层原理简介
  async-profiler 是一个非常强大的工具,使用 jvmti 技术来实现。它的 NB 之处在于它利用了 libjvm.so 中 JVM 内部的 API AsyncGetCallTrace 来获取 Java 函数堆栈,精简后的伪代码如下:static bool vm_init(JavaVM *vm) {     std::cout << "vm_init" << std::endl;          // 从 libjvm.so 中获取 AsyncGetCallTrace 的函数指针句柄     void *libjvm = dlopen("libjvm.so", RTLD_LAZY);     _asyncGetCallTrace = (AsyncGetCallTrace) dlsym(libjvm, "AsyncGetCallTrace"); }  // 事件回调 void recordSample(void *ucontext, uint64_t counter, jint event_type, Event *event) {     std::cout << "Profiler::recordSample: " << std::endl;      ASGCT_CallFrame frames[maxFramesToCapture];      ASGCT_CallTrace trace;     trace.frames = frames;     trace.env = getJNIEnv(g_jvm);      // 调用 AsyncGetCallTrace 获取堆栈     _asyncGetCallTrace(&trace, maxFramesToCapture, ucontext); }
  你可能要说获取个堆栈还需要搞这么复杂,jstack 等工具不是实现得很好了吗?其实不然。
  jstack 等工具获取函数堆栈需要 jvm 进入到 safepoint,对于采样非常频繁的场景,会严重的影响 jvm 的性能,具体的原理不是本次内容的重点这里先不展开。
  async-profiler 除了可以生成热点调用的火焰图,它还提供了 Wall-clock profiling 的功能,这个功能其实就是固定时间采样所有的线程(不管线程当前是 Running、Sleeping 还是 Blocked),它在文档中也提到了,这种方式的 profiling 适合用来分析应用的启动过程,我们姑且用这个不太精确的方式来粗略测量启动阶段耗时在了哪些函数里。
  但是这个工具会抓取所有的线程的堆栈,按这样的方式抓取的 wall-clock 火焰图没法看,不信你看。
  就算你找到了 main 线程,在函数耗时算占比的时候也不太方便,我们关心的其实只是 main 线程(也就是加载 jar 包,执行 spring 初始化的线程),于是我做了一些简单的修改,让 async-profiler 只取抓取 main 线程的堆栈。
  重新编译运行java  -agentpath:/path/to/libasyncProfiler.so=start,event=wall,interval=1ms,threads,file=profile.html -jar xxx.jar
  这样生成的火焰图就清爽多了,这样就知道时间耗在了什么函数上。
  接下来就是分析这个 wall-clock 的火焰图,点开几个调用栈仔细分析,发现很多时间花费在类和资源文件查找和加载(挺失望的,java 连这部分都做不好)
  继续分析代码看看类加载在做什么。Java 垃圾般实现的类查找加载
  Java 地类加载不出意外最终都走到了 java.net.URLClassLoader#findClass 这里。
  这里的 ucp 指的是 URLClassPath,也就是 classpath 路径的集合。对于 SpringBoot 的应用来说,classpath 已经在 META-INF 里写清楚了。Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/
  此次测试的程序 BOOT-INF/lib/ 有 300 多个依赖的 jar 包,当加载某个类时,除了 BOOT-INF/classes/ 之外 Java 居然要遍历那 300 个 jar 包去查看这些 jar 包中是否包含某个类。
  我在 loader.getResource 上注入了一下打印,看看这些函数调用了多少次。
  可以看到太丧心病狂了,加载一个类,居然要调用 loader.getResource 去 jar 包中尝试几百次。我就按二分之一 150 来算,如果加载一万个类,要调用这个函数 150W 次。
  请忽略源码中的 LookupCache 特性,这个特性看起来是为了加速 jar 包查找的,但是这个特性看源码是一个 oracle 商业版的才有的特性,在目前的 jdk 中是无法启用的。(推测,如果理解不对请告知我)
  于是有了一些粗浅的想法,为何不告诉 java 这个类在那个 jar 里?做索引这么天然的想法为什么不实现。
  以下面为例,项目依赖三个 jar 包,foo.jar、bar.jar、baz.jar,其中分别包含了特定包名的类,理想情况下我们可以生成一个索引文件,如下所示。foo.jar com/foo1 com/foo2   bar.jar com/bar com/bar/barbar  baz.jar com/baz
  这就是我们接下来要介绍的 JarIndex 技术。JarIndex 技术
  其实 Jar 在文件格式上是支持索引技术的,称为 JarIndex,通过 jar -i 就可以在 META-INF/ 目录下生成 INDEX.LIST 文件。别高兴的太早,这个 JarIndex 目前无法真正起到作用,有下面几个原因:INDEX.LIST 文件生成不正确,尤其是目前最流行的 fatjar 中包含 jar 列表的情况classloader 不支持(那不是白忙活吗)
  首先来看 INDEX.LIST 文件生成不正确的问题,随便拿一个 jar 文件,使用 jar -i 生成一下试试。JarIndex-Version: 1.0  encloud-api_origin.jar BOOT-INF BOOT-INF/classes BOOT-INF/classes/com BOOT-INF/classes/com/encloud .... META-INF META-INF/maven META-INF/maven/com.encloud META-INF/maven/com.encloud/encloud-api BOOT-INF/lib org org/springframework org/springframework/boot org/springframework/boot/loader org/springframework/boot/loader/jar org/springframework/boot/loader/data org/springframework/boot/loader/archive org/springframework/boot/loader/util
  可以看到在 BOOT-INF/lib 目录中的类索引并没有在这里生成,这里面可是有 300 多个 jar 包。
  同时生成不对的地方还有,org 目录下只有文件夹并没有 class 文件,org 这一行不应该在 INDEX.LIST 文件中。
  第二个缺陷才是最致命的,目前的 classloader 不支持 JarIndex 这个特性。
  所以我们要做两个事情,生成正确的 JarIndex,同时修改 SpringBoot 的 classloader 让其支持 JarIndex。生成正确的 JarIndex
  这个简单,就是遍历 jar 包里的类,将其所在的包名抽取出来。SpringBoot 应用有三个地方存放了 class:BOOT-INF/classesBOOT-INF/libjar 包根目录下 org/springframework/boot/loader
  生成的时候需要考虑到上面的情况,剩下的就简单了。遍历这些目录,将所有的包含 class 文件的包名过滤过来就行。
  大概生成的结果是:JarIndex-Version: 1.0  encloud-api.jar  /BOOT-INF/classes com/encloud com/encloud/app/controller com/encloud/app/controller/v2  / org/springframework/boot/loader org/springframework/boot/loader/archive org/springframework/boot/loader/data org/springframework/boot/loader/jar org/springframework/boot/loader/util  /BOOT-INF/lib/spring-core-4.3.9.RELEASE.jar org/springframework/asm org/springframework/cglib org/springframework/cglib/beans org/springframework/cglib/core  /BOOT-INF/lib/guava-19.0.jar com/google/common/annotations com/google/common/base com/google/common/base/internal com/google/common/cache  ... other jar ...
  除了加载类需要查找,其实还有不少资源文件需要查找,比如 spi 等扫描过程中需要,顺带把资源文件的索引也生成一下写入到 RES_INDEX.LIST 中,原理类似,这里展开。自定义 classloder
  生成了 INDEX.LIST 文件,接下来就是要实现了一个 classloader 能支持一步到位通过索引文件去对应的 jar 包中去加载 class,核心的代码如下:public class JarIndexLaunchedURLClassLoader extends URLClassLoader {     public JarIndexLaunchedURLClassLoader(boolean exploded, Archive rootArchive, URL[] urls, ClassLoader parent) {         super(urls, parent);         initJarIndex(urls); // 根据 INDEX.LIST 创建包名到 jar 文件的映射关系     }          @Override     protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {          Class<?> loadedClass = findLoadedClass(name);         if (loadedClass != null) return loadedClass;          // 如果是 loader 相关的类,则直接加载,不用找了,就在 jar 包的根目录下         if (name.startsWith("org.springframework.boot.loader.") || name.startsWith("com.seewo.psd.bootx.loader.")) {             Class<?> result = loadClassInLaunchedClassLoader(name);             if (resolve) {                 resolveClass(result);             }             return result;              }         // skip java.*, org.w3c.dom.* com.sun.* ,这些包交给 java 默认的 classloader 去处理         if (!name.startsWith("java") && !name.contains("org.w3c.dom.")                  && !name.contains("xml") && !name.startsWith("com.sun")) {             int lastDot = name.lastIndexOf(".");             if (lastDot >= 0) {                 String packageName = name.substring(0, lastDot);                 String packageEntryName = packageName.replace(".", "/");                 String path = name.replace(".", "/").concat(".class");                  // 通过 packageName 找到对应的 jar 包                 List loaders = package2LoaderMap.get(packageEntryName);                 if (loaders != null) {                     for (JarFileResourceLoader loader : loaders) {                         ClassSpec classSpec = loader.getClassSpec(path); // 从 jar 包中读取文件                         if (classSpec == null) {                             continue;                         }                         // 文件存在,则加载这个 class                         Class<?> definedClass = defineClass(name, classSpec.getBytes(), 0, classSpec.getBytes().length, classSpec.getCodeSource());                         definePackageIfNecessary(name);                         return definedClass;                     }                 }             }         }         // 执行到这里,说明需要父类加载器来加载类(兜底)         definePackageIfNecessary(name);         return super.loadClass(name, resolve);     } }
  到这里我们基本上就实现了一个支持 JarIndex 的类加载器,这里的改动经实测效果已经效果非常明显。
  除此之外,我还发现查找一个已加载的类是一个非常高频执行的操作,于是可以在 JarIndexLaunchedURLClassLoader 之前再加一层缓存(思想来自 sofa-boot)public class CachedLaunchedURLClassLoader extends JarIndexLaunchedURLClassLoader {     private final Map classCache = new ConcurrentHashMap<>(3000);      @Override     protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {         return loadClassWithCache(name, resolve);     }     private Class<?> loadClassWithCache(String name, boolean resolve) throws ClassNotFoundException {         LoadClassResult result = classCache.get(name);         if (result != null) {             if (result.getEx() != null) {                 throw result.getEx();             }             return result.getClazz();         }          try {             Class<?> clazz = super.findLoadedClass(name);             if (clazz == null) {                 clazz = super.loadClass(name, resolve);             }             if (clazz == null) {                 classCache.put(name, LoadClassResult.NOT_FOUND);             }             return clazz;         } catch (ClassNotFoundException exception) {             classCache.put(name, new LoadClassResult(exception));             throw exception;     } }
  注意:这里为了简单示例直接用 ConcurrentHashMap 来缓存 class,更好的做法是用 guava-cache 等可以带过期淘汰的 map,避免类被永久缓存。如何不动 SpringBoot 的代码实现 classloader 的替换
  接下的一个问题是如何不修改 SpringBoot 的情况下,把 SpringBoot 的 Classloader 替换为我们写的呢?
  大家都知道,SpringBoot 的 jar 包启动类其实并不是我们项目中写的 main 函数,其实是
  org.springframework.boot.loader.JarLauncher,这个类才是真正的 jar 包的入口。package org.springframework.boot.loader;  public class JarLauncher extends ExecutableArchiveLauncher {  	public static void main(String[] args) throws Exception { 		new JarLauncher().launch(args); 	} }
  那我们只要替换这个入口类就可以接管后面的流程了。如果只是替换那很简单,修改生成好的 jar 包就可以了,但是这样后面维护的成本比较高,如果在打包的时候就替换就好了。SpringBoot 的打包是用 spring-boot-maven-plugin 插件     org.springframework.boot     spring-boot-maven-plugin 
  最终生成的 META-INF/MANIFEST.MF 文件如下$ cat META-INF/MANIFEST.MF Manifest-Version: 1.0 Implementation-Title: encloud-api Implementation-Version: 2.0.0-SNAPSHOT Archiver-Version: Plexus Archiver Built-By: arthur Implementation-Vendor-Id: com.encloud Spring-Boot-Version: 1.5.4.RELEASE Implementation-Vendor: Pivotal Software, Inc. Main-Class: org.springframework.boot.loader.JarLauncher Start-Class: com.encloud.APIBoot Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Created-By: Apache Maven 3.8.5 Build-Jdk: 1.8.0_332 Implementation-URL: http://projects.spring.io/spring-boot/parent/enclo  ud-api/
  为了实现我们的需求,就要看 spring-boot-maven-plugin 这个插件到底是如何写入 Main-Class 这个类的,经过漫长的 maven 插件源码的调试,发现这个插件居然提供了扩展点,可以支持修改 Main-Class,它提供了一个 layoutFactory 可以自定义     org.springframework.boot     spring-boot-maven-plugin                                            repackage                                                                                                 com.seewo.psd.bootx             bootx-loader-tools             0.1.1               
  实现这个package com.seewo.psd.bootx.loader.tools;  import org.springframework.boot.loader.tools.*;  import java.io.File; import java.io.IOException; import java.util.Locale;  public class MyLayoutFactory implements LayoutFactory {     private static final String NESTED_LOADER_JAR = "META-INF/loader/spring-boot-loader.jar";     private static final String NESTED_LOADER_JAR_BOOTX = "META-INF/loader/bootx-loader.jar";          public static class Jar implements RepackagingLayout, CustomLoaderLayout {         @Override         public void writeLoadedClasses(LoaderClassesWriter writer) throws IOException {             // 拷贝 springboot loader 相关的文件到 jar 根目录             writer.writeLoaderClasses(NESTED_LOADER_JAR);             // 拷贝 bootx loader 相关的文件到 jar 根目录             writer.writeLoaderClasses(NESTED_LOADER_JAR_BOOTX);          }          @Override         public String getLauncherClassName() {             // 替换为我们自己的 JarLauncher             return "com.seewo.psd.bootx.loader.JarLauncher";         }     } }
  接下来实现我们自己的 JarLauncherpackage com.seewo.psd.bootx.loader;  import java.net.URL;  public class JarLauncher extends org.springframework.boot.loader.JarLauncher {      @Override     protected ClassLoader createClassLoader(URL[] urls) throws Exception {         return new CachedLaunchedURLClassLoader(urls, getClass().getClassLoader());     }      public static void main(String[] args) throws Exception {         new JarLauncher().launch(args);     } }
  重新编译就可以实现替换$ cat META-INF/MANIFEST.MF Manifest-Version: 1.0 ... Main-Class: com.seewo.psd.bootx.loader.JarLauncher ...
  到这里,我们就基本完成所有的工作,不用改一行业务代码,只用改几行 maven 打包脚本,就可以实现支持 JarIndex 的类加载实现。优化效果
  我们来看下实际的效果,项目 1 稍微小型一点,启动耗时从 70s 降低到 46s
  第二个 jar 包更大一点,效果更明显,启动耗时从 220s 减少到 123s
  未完待续
  其实优化到这里,还远远没有达到我想要的目标,为什么启动需要这么长时间,解决了类查找的问题,那我们来深挖一下 Spring 的初始化。
  Spring bean 的初始化是串行进行的,于是我先来做一个可视化 timeline,看看到底是哪些 Bean 耗时很长。Spring Bean 初始化时序可视化
  因为不会写前端,这里偷一下懒,利用 APM 的工具,把数据上报到 jaeger,这样我们就可以得到一个包含调用关系的timeline 的界面了。jaeger 的网址在这里:www.jaegertracing.io/
  首先我们继承 DefaultListableBeanFactory 来对 createBean 的过程做记录。public class BeanLoadTimeCostBeanFactory extends DefaultListableBeanFactory {      private static ThreadLocal> parentStackThreadLocal = new ThreadLocal<>();       @Override     protected Object createBean(String beanName, RootBeanDefinition rbd, Object[] args) throws BeanCreationException {         // 记录 bean 初始化开始         Object object = super.createBean(beanName, rbd, args);         // 记录 bean 初始化结束         return object;     }
  接下来我们实现 ApplicationContextInitializer,在 initialize 方法中替换 beanFactory 为我们自己写的。public class BeanLoadTimeCostApplicationContextInitializer implements ApplicationContextInitializer, Ordered {     public BeanLoadCostApplicationContextInitializer() {         System.out.println("in BeanLoadCostApplicationContextInitializer()");     }      @Override     public void initialize(ConfigurableApplicationContext applicationContext) {         if (applicationContext instanceof GenericApplicationContext) {             System.out.println("BeanLoadCostApplicationContextInitializer run");             BeanLoadTimeCostBeanFactory beanFactory = new BeanLoadTimeCostBeanFactory();             Field field = GenericApplicationContext.class.getDeclaredField("beanFactory");             field.setAccessible(true);             field.set(applicationContext, beanFactory);         }     } }
  接下来将记录的状态上报到 jaeger 中,实现可视化堆栈显示。public void reportBeanCreateResult(BeanCreateResult beanCreateResult) {         Span span = GlobalTracer.get().buildSpan(beanCreateResult.getBeanClassName()).withStartTimestamp(beanCreateResult.getBeanStartTime() * 1000).start();          try (Scope ignore = GlobalTracer.get().scopeManager().activate(span)) {             for (BeanCreateResult item : beanCreateResult.getChildren()) {                 Span childSpan = GlobalTracer.get().buildSpan(item.getBeanClassName()).withStartTimestamp(item.getBeanStartTime() * 1000).start();                  try (Scope ignore2 = GlobalTracer.get().scopeManager().activate(childSpan)) {                     printBeanStat(item);                 } finally {                     childSpan.finish(item.getBeanEndTime() * 1000);                 }             }         } finally {             span.finish(beanCreateResult.getBeanEndTime() * 1000);         } }
  通过这种方式,我们可以很轻松的看到 spring 启动阶段 bean 加载的 timeline,生成的图如下所示。
  这对我们进一步优化 bean 的加载提供了思路,可以看到 bean 的依赖关系和加载耗时具体耗在了哪个 bean。通过这种方式可以在 SpringBean 串行加载的前提下,把 bean 的加载尽可能的优化。SpringBean 的依赖分析
  更好一点的方案是基于 SpringBean 的依赖关系做并行加载。这个特性 2011 年前就有人提给了 Spring,具体看这个 issue:github.com/spring-proj…
  就在去年,还有人去这个 issue 下去恭祝这个 issue 10 周年快乐。
  做并行加载确实有一些难度,真实项目的 Spring Bean 依赖关系非常复杂,我把 Spring Bean 的依赖关系导入到 neo4j 图数据库,然后进行查询MATCH (n) RETURN n;
  得到的图如下所示。一方面 Bean 的数量特别多,还有复杂的依赖关系,以及循环依赖。
  基于此依赖关系,我们是有机会去做 SpringBean 的并行加载的,这部分还没实现,希望后面有机会可以完整的实现这块的逻辑,个人感觉可以做到 10s 内启动完一个超大的项目。Java 启动优化的其它技术
  Java 启动的其它技术还有 Heap Archive、CDS,以及 GraalVM 的 AOT 编译,不过这几个技术目前都有各自的缺陷,还无法完全解决目前我们遇到的问题。后记
  这篇文章中用到的技术只是目前比较粗浅的尝试,如果大家有更好的优化,可以跟我交流,非常感谢。
  作者:挖坑的张师傅
  链接:https://juejin.cn/post/7117815437559070734

俄罗斯3娃教练成叛徒!清空社媒账号飞往美国,或面临被逮捕近日有不少粉丝关注到了俄罗斯三娃的最新动态,俄罗斯三娃在结束了国内的相关活动之后,选择了出海度假,其中K宝和莎莎一起出游,两人换上精致的泳装,笑得非常开心,而千金则是和家人们一起在肖华谈季中锦标赛理念大家不该只为总冠军而战据TheAthletic记者ShamsCharania报道,NBA正在讨论一项新的季中锦标赛,最快可能会在202324赛季开始实行,大概的思路是在12月份进行小组赛,圣诞前打完14哈登,到底值不值顶薪据外国内媒体透露,现在哈登想要顶薪留守76人,但是76人的管理层认为哈登不值顶薪,想要让哈登降薪续约。其实放眼整个联盟而言,在后卫这个位置上,哈登还是属于绝对的上游,只要哈登愿意,单场18次罚球,狂轰4195!巴特勒得分王,带队迎东决开门红北京时间5月18日,NBA季后赛正如火如荼地继续进行。而目前打进东决的迈阿密热火队,也在主场迎来了波士顿凯尔特人队的挑战。双方作为东决舞台上的老对手,两年前就曾有过较量,但那时的绿重返CBA执教!广东宏远功勋老臣加盟上海男篮,李春江挖人成功去年休赛期广东队的视频分析师庞启蒙加盟了上海队,庞启蒙是CBA第一个视频分析师,李春江去上海队当主教练后,就从广东队挖走了庞启蒙,李春江对庞启蒙有知遇之恩,面对恩师的邀请,庞启蒙难正午阳光十大经典剧开端第九,大江大河第六NO。10知否知否应是绿肥红瘦首先正午阳光出品,服化道精致,只是这集数真的很磨人,但同时更好讲述剧中人物的众生相和立场出发点,明兰里面人间清醒活得通透拎得清也看得明,疯狂金句频出,美足协与男女国家队工会达协议将实现同工同酬,世界杯奖金等额直播吧5月18日讯美国足协官网发布公告,宣布美国足球联合会(USSF),美国女子国家队球员协会(USWNTPA)和美国国家足球队球员协会(USNSTPA)已同意了一项具有历史意义的2023中国亚洲杯为何会被取消易主?越媒这要求亚洲国家都做不到球迷们非常期待2023年中国亚洲杯赛事,但是大家在期待的同时也担心国外球员的入境会影响到中国的疫情,毕竟国内外对待疫情的政策不同,这一点是必须要考虑在内的。中国为此次的亚洲杯赛事做浙江绝美的峡谷风光,有的美上国家地理,有的堪称浙江青藏高原对于热爱户外旅行的我来说,领略祖国的大好河山,是一件极其令人向往的事,因为这让我在沉浸于秀美山水风光的同时,也不禁为大自然造物的神奇而惊叹。诗画浙江,山水奇秀古韵悠长风光独好,总是国家男女篮集训名单出炉郑薇接任女篮主教练5月17日,中国篮球协会官方宣布,正式聘任郑薇担任中国女篮主教练。2022年中国女篮中国男篮集训名单同时公布。据悉,为备战2022年女篮世界杯,中国女篮计划于2022年5月21日在顶薪续约进国家队!郭艾伦老搭档,场均18分,杜锋用他代替周鹏刚结束的CBA联赛里,深圳队度过了一个不成功的赛季,常规赛阶段成绩很好,排名第6,并且展现了强大的整体实力,只是没想到季后赛出现意外情况,首轮轻松跨过山东之后,8进4对阵上海时出现
英伟达威胁中国自动驾驶?专家国内真正愿意行动的没几个中国新能源汽车到处开花,个个都喊着自己有自动驾驶技术,但真正愿意行动的企业却没有几个。这句话出现在中国2022年电动汽车百人论坛大会上,而作为此次的演讲人专家和前工信部部长,谈及中中国最美的14座小县城,各有各的美,你去过几座?中国人最烟火的生活下沉在各个小县城里有人说,北上广深是中国人的面子,而广大的农村小镇县城,才是中国人的里子。现代化的大都市,高楼大厦诚然繁华,却也千篇一律但1400多个小县城,却各长这么大,只有一件事百思不得其解,中国足球为何越踢越窝囊?改革开放后,中国各行各业都突飞猛进,成绩耀眼,综合国力陡然提升,如坐火箭般嗖地直冲云霄。可以毫不夸张地说,当今中国在世界上的威望已经处在坐二望一的位置了,是任何势力都不敢小觑的东方神舟十三号成功着陆!灯塔涂料添新功慧正资讯据中国载人航天工程办公室消息,北京时间2022年4月16日09时56分,神舟十三号载人飞船返回舱在东风着陆场成功着陆,现场医监医保人员确认航天员翟志刚王亚平叶光富身体状态良猛龙季后赛G176人131111猛龙!各种最坏的情况同时爆发猛龙与76人的系列赛首战,最终由76人以131111击溃猛龙,以20分之差拿下胜利。一泰里斯马克西与托拜厄斯哈里斯的强势助拳。猛龙本场仍然强力执行限制詹姆斯哈登与乔尔恩比德的策略,6个月的驻守任务结束,神舟十三号带宇航员回家辛苦了天宫课堂第二课结束半个多月了,不知道大家还记得空间站内的三位老师吗?告诉大家一个好消息,随着驻守任务的结束,在空间站内出差了半年的出差三人组就要回来啦!神舟十三号将带着三位宇航员回中国天宫空间站两个月无航天员值守,外国飞船能偷偷对接吗?2022年4月16日,神舟十三号飞船载着三名航天员顺利返回东风着陆场,完成了空间站验证阶段全部任务目标。按照计划,天舟三号货运飞船将转移到天和核心舱前向对接口,5月份发射天舟四号货三孩时代,95的月子会所出现亏损情况,行业乱象该如何治理很多人都非常好奇,为什么国外的人生完孩子之后不需要坐月子,而中国女性就需要坐月子呢?即便是同为亚洲人的许多国家,都没有坐月子这一说法,但是在中国就有,并且中国人是非常重视坐月子的。谷雨之福,更是在那秋后的五谷丰登里文龙行天下之波哥图网络窗外的雨淅淅沥沥地下着。轻开门窗,望着雨幕,我发现这雨落的是一种别样的风景,雨滴大如米粒,不急不躁温和地垂直而下,白茫茫的一片,犹如一张偌大的白色幕帘遮掩着远无论你多善良,面对有些人,必须翻脸文唯晨菜根谭有云害人之心不可有,防人之心不可无。人生想过得顺利,就必须要有防人之心。一个对别人毫无防备的人,一不小心就会跌入深渊。我们可以善良,但不能太好说话,如果你总是因为别人的人生就是一个熬字忙完一天又一天,冬去春来年复年,除去吃穿剩无几,唯有额头皱纹添,贫贱富贵皆看淡,生死不求庙中仙。青年男女结婚以后,告别了花前月下的浪漫日子,面对的是油盐柴米酱醋茶锅碗瓢盆交响曲等非