首页 文章 精选 留言 我的

精选列表

搜索[国产神器],共5639篇文章
优秀的个人博客,低调大师

破案神器?新大脑扫描技术可视觉化你的想象

本周荷兰研究团队表示,结合高分辨率核磁共振成像、计算建模,他们已经可以图像勾勒出大脑的想象了,就像变成一个内部颅相机,可随时扫描大脑活动。多年来视觉和认知信息如何在大脑中显示一直是个未解之谜,而这次终于把概念上的进步提升到技术上来了。 MRI图像主要是用于大规模分析大脑在特定任务时的“吃氧”工作,这个研究主要研究大脑小规模的活动,它们的MRI数据以2 x2x2毫米单位为像素点。电脑产生的活动就是以这些像素点为基础形成3D图像的。 为了通俗化,该团队为不同大脑的想象活动创建了一个相关的“图书馆”,不同的想象活动就会有不同的字母呈现。到时候看字母就可以知道你在想什么啦, 如果把字母连贯起来,就会侦查你一系列的活动,非常可怕~ 我们自己的头大脑依据感官信息和经验构造图像会有特定的算法,该研究团队就是采用类似的算法,本质上就是把大脑图像像素点翻

优秀的个人博客,低调大师

后台任务队列管理神器 Android-Priority-Job-Queue

有人说“Android的开发,玩的就是多线程”。从某个角度来说的确如此,现在的App被设计的越来越复杂,相信很多开发人员都因大量而又复杂的后台任务(background work)而焦头烂额:Async-Task和Activity的生命周期太过于耦合,虽然实现简单但是对于重要的后台任务还是不靠谱;Loaders虽然可以用于异步从磁盘列读取数据,但是对于异步的网络请求就无能为力了;相对给力点的方案是后台服务中开辟进程池(Thread Pool),使用ThreadPoolExecutor来帮助管理线程,但是app越复杂后台操作越多,需要处理的多线程的问题越多,想一想就头大..... 但是各位读者不要沮丧,今天就是向大家介绍一个后台任务队列管理库Android-Priority-Job-Queue,它将提供一个优雅的架构来解决以上所有的问题! 1. 简介 用官方的话来说,Android-Priority-Job-Queue是一款专门为Android平台编写的,实现了Job Queue的后台任务队列类库,能够轻松的在后台执行定时任务,并且提高了用户体验和应用的稳定性。其设计理念以灵活性和功能性为主,并且一直在更新。 “Priority Job Queue is an implementation of a Job Queue specifically written for Android to easily schedule jobs (tasks) that run in the background, improving UX and application stability.” It is written primarily with flexibility & functionality in mind. This is an ongoing project, which we will continue to add stability and performance improvements. github : https://github.com/yigit/android-priority-jobqueue 在这里可以了解到更多更全面的介绍。 其使用框架也很简便直接: 构造一个任务管理器JobManager,为我们管理任务; 自定义Job类,来作为任务的载体; 在需要时,将自定义的Job类实例加入到JobManager中; 这样就OK了,JobManager会根据优先级、持久性、负载平衡、延迟,网络控制、分组等因素来管理任务的执行。由于是独立于各个Activity,JobManager为Job的执行提供了一个很好的生命周期,用户体验更为棒。是不是很惊喜!闲话少叙,我们来看使用范例吧! 2. 使用实例 2.1 添加方法 在Android Studio添加,如下引用: dependencies { compile 'com.birbit:android-priority-jobqueue:2.0.1' } 如果你很怀旧,还在坚持使用Eclipse,那就在maven这样配置: <dependency> <groupId>com.birbit</groupId> <artifactId>android-priority-jobqueue</artifactId> <version>2.0.1</version> </dependency> 2.2 配置JobManager JobManager是整个框架的核心。作为一个重型的对象,建议Application只构建一个JobManager实例供全局使用。另一方面,为了让任务的执行有一个更好的生命周期,建议将JobManager放在Application类,而不是一个具体的Activity。以下是示例代码: import android.app.Application; import android.util.Log; import com.path.android.jobqueue.JobManager; import com.path.android.jobqueue.config.Configuration; import com.path.android.jobqueue.log.CustomLogger; public class JobQueueApplication extends Application { private JobManager jobManager; private static JobQueueApplication instance; @Override public void onCreate() { super.onCreate(); instance = this;//1. Application的实例 configureJobManager();//2. 配置JobMananger } //私有构造器 private JobQueueApplication(){ instance=this; } public JobManager getJobManager() { return jobManager; } public static JobQueueApplication getInstance() { return instance; } private void configureJobManager() { //3. JobManager的配置器,利用Builder模式 Configuration configuration = new Configuration.Builder(this) .customLogger(new CustomLogger() { private static final String TAG = "JOBS"; @Override public boolean isDebugEnabled() { return true; } @Override public void d(String text, Object... args) { Log.d(TAG, String.format(text, args)); } @Override public void e(Throwable t, String text, Object... args) { Log.e(TAG, String.format(text, args), t); } @Override public void e(String text, Object... args) { Log.e(TAG, String.format(text, args)); } }) .minConsumerCount(1)//always keep at least one consumer alive .maxConsumerCount(3)//up to 3 consumers at a time .loadFactor(3)//3 jobs per consumer .consumerKeepAlive(120)//wait 2 minute .build(); jobManager = new JobManager(this, configuration); } } 以上是整个自定义Application类的代码,其逻辑很清晰。首先为Application类设置单例模式,并保存私有变量jobManager;然后在onCreate()中调用configureJobManager方法来完成jobManager的初始化。我们来看下在其初始化参数Configuration实例中都配置了哪些内容: CustomLogger:日志设置,便于用户查看任务队列的工作信息,在调试的过程中很有用,后面分析JobManager的任务调度时就会用到; minConsumerCount&maxConsumerCount: 最少消费者和最多消费者数量,所谓的消费者就是开启的线程,用来执行任务。任务队列实际上就是一个生产者和消费者问题,用户是生产者,提交任务(Job),开启的线程就是消费者来执行任务,任务被执行就是“消费”。这里所谓的最少和最大将会下面具体解释; loadFactor(int): 其意义是设置多少个任务为一组被分配个一个消费者(Thread),也就是一个Thread最多要“承包”几个任务来执行; consumerKeepAlive :设置消费者在没有任务的情况下保持存活的时长,以秒为单位,如果过了这个时长还没有任务,消费者线程就会被回收; Configuration以建筑者模式来链式配置,对此不是很熟悉的读者可以参考如何构建含有大量参数的构造器:浅谈Builder Pattern的使用和链式配置. 有了JobManger自然还需要Job,下面就来看看如何设置Job. 2.3 Job 自定义的Job类需要继承Android-Priority-Job-Queue提供的Job类,下面就是是一个简单的范例,这个任务的内容就是睡眠5秒。 import android.util.Log; import com.path.android.jobqueue.Job; import com.path.android.jobqueue.Params; import com.path.android.jobqueue.RetryConstraint; public class MyJob extends Job{ public static final int PRIORITY = 1; private String text; String TAG = "Myjob"; int sleepTime; public MyJob(String text) { // A job should be persisted in case the application exits // before job is completed. super(new Params(PRIORITY).persist()); this.text = text; sleepTime = 5; Log.i(TAG, text+" goin"); } @Override public void onAdded() { // Job has been saved to disk. // This is a good place to dispatch a UI event // to indicate the job will eventually run. Log.i(TAG, text+" Onadded"); } @Override public void onRun() throws Throwable { // Job logic goes here. // All work done here should be synchronous, // a job is removed from the queue once onRun() finishes. Thread.sleep(sleepTime*1000); Log.i(TAG, text+" onRun"); } @Override protected RetryConstraint shouldReRunOnThrowable(Throwable throwable, int runCount, int maxRunCount) { // An error occurred in onRun. // Return value determines whether this job should retry or cancel. You can further // specify a backoff strategy or change the job's priority. You can also apply the // delay to the whole group to preserve jobs' running order. return RetryConstraint.createExponentialBackoff(runCount, 10); } @Override protected void onCancel() { } } Job类的模块很清晰,我们只需要按照要求覆盖以下方法即可: 在构造器,利用Params类中配置参数; onAdded(): 任务加入队列并被保存在硬盘上,定义此时要处理的逻辑; onRun(): 任务开始执执行,在此定义任务的主题逻辑,当执行完毕后,任务将被从任务队列中删除; onCancel():任务取消的时候要执行的逻辑; shouldReRunOnThrowable():当onRun()方法中抛出异常时,就会调用该函数,该函数返回Job类在执行发生异常时的应对策略,是重新执行还是取消,或者是一定时间之后再尝试。 在这里特别说明下Params类,通过该类可以配置Job类的各种信息,同样也采用类Builder Pattern的链式配置: 默认构造器传入的是int参数是该任务的优先级,优先级越高,越优先执行。 public Params(int priority) { this.priority = priority; } requireNetwork(): 设置该任务要求访问网络; groupBy(String groupId):设置组ID,被设置相同组ID的任务,将会按照顺序执行; persist():设置任务为可持久化的,持久化要求Job类为序列化的,这一点并不意外,因为一个类的内容只有序列化之后才能变成字节模式保存在硬盘上; delayInMs(long delayMs):设置延迟时间,ms为单位,在该时间之后再放入任务队列中。 2.4 执行任务 Job的执行很简单,就把任务类加入到任务队列中即可以。 public class MainActivity extends AppCompatActivity { private JobManager jobManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btn_start = (Button)findViewById(R.id.start_job_button); //JobManager对象 jobManager = JobQueueApplication.getInstance().getJobManager(); btn_start.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { for(int i=0; i<9 ;i++) { //将任务加入后台队列中 jobManager.addJobInBackground(new MyJob(“"+i)); } } }); } } 在一个Activity中点击Button,就会把9个MyJob实例加入到后台队列中。其运行效果如下: 03-25 21:44:47.207 I/Myjob: 0 goin 03-25 21:44:47.208 I/Myjob: 1 goin 03-25 21:44:47.208 I/Myjob: 2 goin 03-25 21:44:47.208 I/Myjob: 3 goin 03-25 21:44:47.208 I/Myjob: 4 goin 03-25 21:44:47.208 I/Myjob: 5 goin 03-25 21:44:47.208 I/Myjob: 6 goin 03-25 21:44:47.208 I/Myjob: 7 goin 03-25 21:44:47.208 I/Myjob: 8 goin 03-25 21:44:47.218 I/Myjob: 0 Onadded 03-25 21:44:47.228 I/Myjob: 1 Onadded 03-25 21:44:47.241 I/Myjob: 2 Onadded 03-25 21:44:47.251 I/Myjob: 3 Onadded 03-25 21:44:47.260 I/Myjob: 4 Onadded 03-25 21:44:47.274 I/Myjob: 5 Onadded 03-25 21:44:47.280 I/Myjob: 6 Onadded 03-25 21:44:47.291 I/Myjob: 7 Onadded 03-25 21:44:47.307 I/Myjob: 8 Onadded 03-25 21:44:52.235 I/Myjob: 1 onRun 03-25 21:44:52.267 I/Myjob: 4 onRun 03-25 21:44:52.297 I/Myjob: 7 onRun 03-25 21:44:57.250 I/Myjob: 8 onRun 03-25 21:44:57.282 I/Myjob: 6 onRun 03-25 21:44:57.310 I/Myjob: 5 onRun 03-25 21:45:02.264 I/Myjob: 3 onRun 03-25 21:45:02.299 I/Myjob: 2 onRun 03-25 21:45:02.324 I/Myjob: 0 onRun 为了便于查看,这里输出的日志信息只保留最主要的内容,我们可以看到任务0-8依次启动并加入到任务队列中,然后再被执行,JobManager帮你管理了一切,完美! 有的读者可能已经发行了,任务0-8的执行顺序是混乱的,这就涉及到Android-Priority-JobQueue任务的调度问题,也是本人最好兴趣的内容。 3. 任务调度分析 回顾一下,我们对JobManager的设置:至少一个消费者线程,至多三个;每个消费者线程最多处理三个任务。这些设置就是在影响任务调度。 当一个任务要加入任务队列时,会做出如下的判断: 首先计算当前能处理的任务数的最大值(CurrentTaskCapacity)= 已启动的消费线程数(CurrentThreadNum) * 每个线程处理任务的容量(PerThreadTaskCapacity); CurrentTaskCapacity = CurrentThreadNum * PerThreadTaskCapacity 如果当前任务数加上现在要加入任务,小于或等于CurrentTaskCapacity,则将该任务加入到任务队列中; 如果当前任务数加上现在要加入任务,大于CurrentTaskCapacity,则判断CurrentThreadNum是不是已经达到设置的最大值,如果没有就开辟新的消费者线程来承担任务; 如果CurrentTaskCapacity和CurrentThreadNum都达到上限,那就对不起了,该任务就不能加入队列,需要等到有任务执行完毕,任务容量又有了空余时才能进入队列等待执行。 如何验证上面结论呢?还记得我们在Application类中配置JobManager时设置的日志信息吗? 这个时候它就发挥作用了,下面是任务0-8加入到任务队列中时输出的日志,内容很多,请注意的表黑的部分: 03-25 21:44:47.218 D/JOBS: added job id: 84 class: MyJob priority: 0 delay: 0 group : null persistent: true requires network: false 03-25 21:44:47.218 I/Myjob: 0 Onadded 03-25 21:44:47.222 D/JOBS: pool-1-thread-1: load factor check. true = (0 < 1)|| (0 * 3 < 1 + 0). consumer thread: false 03-25 21:44:47.222 D/JOBS: adding another consumer 03-25 21:44:47.223 D/JOBS:** starting consumer Thread-177** 03-25 21:44:47.224 D/JOBS: looking for next job 03-25 21:44:47.224 D/JOBS: running groups 03-25 21:44:47.224 D/JOBS: non persistent result null 03-25 21:44:47.228 D/JOBS: added job id: 85 class: MyJob priority: 1 delay: 0 group : null persistent: true requires network: false 03-25 21:44:47.228 I/Myjob: 1 Onadded 03-25 21:44:47.234 D/JOBS: persistent result com.path.android.jobqueue.JobHolder@55 03-25 21:44:47.234 D/JOBS: running job MyJob 03-25 21:44:47.237 D/JOBS: pool-1-thread-1: load factor check. false = (1 < 1)|| (1 * 3 < 1 + 1). consumer thread: false 03-25 21:44:47.241 D/JOBS: added job id: 86 class: MyJob priority: 2 delay: 0 group : null persistent: true requires network: false 03-25 21:44:47.241 I/Myjob: 2 Onadded 03-25 21:44:47.245 D/JOBS: pool-1-thread-1: load factor check. false = (1 < 1)|| (1 * 3 < 2 + 1). consumer thread: false 03-25 21:44:47.251 D/JOBS: added job id: 87 class: MyJob priority: 3 delay: 0 group : null persistent: true requires network: false 03-25 21:44:47.251 I/Myjob: 3 Onadded 03-25 21:44:47.255 D/JOBS: pool-1-thread-1: load factor check. true=(1 < 1) || (1 * 3 < 3 + 1). consumer thread: false 03-25 21:44:47.255 D/JOBS: adding another consumer 03-25 21:44:47.256 D/JOBS: starting consumer Thread-178 03-25 21:44:47.257 D/JOBS: looking for next job 03-25 21:44:47.257 D/JOBS: running groups 03-25 21:44:47.257 D/JOBS: non persistent result null 03-25 21:44:47.260 D/JOBS: added job id: 88 class: MyJob priority: 4 delay: 0 group : null persistent: true requires network: false 03-25 21:44:47.260 I/Myjob: 4 Onadded 03-25 21:44:47.264 D/JOBS: persistent result com.path.android.jobqueue.JobHolder@58 03-25 21:44:47.264 D/JOBS: running job MyJob 03-25 21:44:47.270 D/JOBS: pool-1-thread-1: load factor check. false = (2 < 1)|| (2 * 3 < 3 + 2). consumer thread: false 03-25 21:44:47.274 D/JOBS: added job id: 89 class: MyJob priority: 5 delay: 0 group : null persistent: true requires network: false 03-25 21:44:47.274 I/Myjob: 5 Onadded 03-25 21:44:47.277 D/JOBS: pool-1-thread-1: load factor check. false = (2 < 1)|| (2 * 3 < 4 + 2). consumer thread: false 03-25 21:44:47.280 D/JOBS: added job id: 90 class: MyJob priority: 6 delay: 0 group : null persistent: true requires network: false 03-25 21:44:47.280 I/Myjob: 6 Onadded 03-25 21:44:47.283 D/JOBS: pool-1-thread-1: load factor check. true = (2 < 1)|| (2 * 3 < 5 + 2). consumer thread: false 03-25 21:44:47.283 D/JOBS: adding another consumer 03-25 21:44:47.287 D/JOBS: starting consumer Thread-179 03-25 21:44:47.288 D/JOBS: looking for next job 03-25 21:44:47.288 D/JOBS: running groups 03-25 21:44:47.288 D/JOBS: non persistent result null 03-25 21:44:47.291 D/JOBS: added job id: 91 class: MyJob priority: 7 delay: 0 group : null persistent: true requires network: false 03-25 21:44:47.291 I/Myjob: 7 Onadded 03-25 21:44:47.295 D/JOBS: persistent result com.path.android.jobqueue.JobHolder@5b 03-25 21:44:47.295 D/JOBS: running job MyJob 03-25 21:44:47.302 D/JOBS: pool-1-thread-1: load factor check. false = (3 < 1)|| (3 * 3 < 5 + 3). consumer thread: false 03-25 21:44:47.306 D/JOBS: added job id: 92 class: MyJob priority: 8 delay: 0 group : null persistent: true requires network: false 03-25 21:44:47.307 I/Myjob: 8 Onadded 03-25 21:44:47.310 D/JOBS: pool-1-thread-1: load factor check. false = (3 < 1)|| (3 * 3 < 6 + 3). consumer thread: false 日志中这样的load factor check. true = (0 < 1)|| (0 * 3 < 1 + 0)计算表达式,就是在进行线程调度的判定,当计算表达式为true时,就意味着要启动新的消费者进程。 ||右边括号内的表达式就是在比较当前任务数和当前任务容量。 通过日志我们可以看到,面对任务0-8,JobManager依次启动了三个消费者进程,并将这9个任务分配给他们: Thread-177:任务0、1、2; Thread-178:任务3、4、5; Thread-179:任务6、7、8; 三个消费者线程并发执行,由于所有任务的优先级都是一样的,消费者线程们就会随机执行任务。 消费者线程被创建,自然也会被回收,这才是完整的生命周期。以下是当任务执行完成时日志的输出: 03-25 21:47:02.280 D/JOBS: Thread-177: load factor check. false = (2 < 1)|| (2 * 3 < 0 + 0). consumer thread: true 03-25 21:47:02.280 D/JOBS: finishing consumer Thread-177 03-25 21:47:02.310 D/JOBS: Thread-178: load factor check. false = (1 < 1)|| (1 * 3 < 0 + 0). consumer thread: true 03-25 21:47:02.310 D/JOBS: finishing consumer Thread-178 03-25 21:47:02.337 D/JOBS: Thread-179: load factor check. true = (0 < 1)|| (0 * 3 < 0 + 0). consumer thread: true 03-25 21:47:02.337 D/JOBS: didn't allow me to die, re-running Thread-179 03-25 21:47:02.337 D/JOBS: re-running consumer Thread-179 我们可以看到,当任务执行完毕之后Thread-177和Thread-178都被回收了,但是由于我们设置了最小消费者线程数为1,所以Thread-179被留下“坚守岗位”,等待下一个任务的到来,直到超时。 由此可知,JobMananger的任务调度机制还是十分复杂和完备的,真庆幸已经有人帮我们实现了。 4. RetryConstraint 最后要说的就是RetryConstraint,即任务在执行中发生异常之后要执行的策略。用户可以根据自己的使用情况来设置: RETRY: RetryConstraint的自带策略,立刻重新尝试执行策略,直到执行成功或者尝试次数达到最大(18次); CANCEL:RetryConstraint的自带策略,取消当前任务的执行; *createExponentialBackoff(int runCount, long initialBackOffInMs) *:定期延迟尝试执行任务,如果任务执行失败,下次执行的延迟时间会以指数形式增长,最大尝试次数为20次; public static RetryConstraint createExponentialBackoff(int runCount, long initialBackOffInMs) { RetryConstraint constraint = new RetryConstraint(true); constraint.setNewDelayInMs(initialBackOffInMs * (long) Math.pow(2, Math.max(0, runCount - 1))); return constraint; } 在官方给出的示例PostTweet中,是这样定义* RetryConstraint*的: @Override protected RetryConstraint shouldReRunOnThrowable(Throwable throwable, int runCount, int maxRunCount) { if(throwable instanceof TwitterException) { //if it is a 4xx error, stop TwitterException twitterException = (TwitterException) throwable; int errorCode = twitterException.getErrorCode(); return errorCode < 400 || errorCode > 499 ? RetryConstraint.RETRY : RetryConstraint.CANCEL; } return RetryConstraint.RETRY; } 如果是4XX的错误(服务器错误)就取消访问,其他异常就离开重新尝试请求。 关于Android-Priority-JobQueue,今天先介绍到这里,内容已经够多了。总之,这是一个很优秀的任务队列管理库,很值得使用和研究。欢迎大家尝试,以及给我留言指教。 阅读参考: Android Priority Job Queue 入门 如何构建含有大量参数的构造器:浅谈Builder Pattern的使用和链式配置 Java序列化心得(一):序列化设计和默认序列化格式的问题 Java序列化心得(二):自定义序列化 Android Priority Job Queue (Job Manager):线程任务的容错重启机制(二)

优秀的个人博客,低调大师

Beetl 模板引擎 3.19.1,国产高速模版引擎

Beetl 研发自 2010 年,国内流行 Java 模板引擎 文档源码在线体验模板性能测试表达式引擎性能测试性能优化指南 本次发布修复了自定义HTML标签的配置BUG,Beetl同其他模版语言有许多不同的地方,其中一个重要不同在于能自定义定界符和站位符,包括 自定义定界符,如<% <? # 等任意符号 自定义占位符,如${},#{} 等任意符号 自定义HTML标签,如<#topic name=""/> 或者 <yourPeffix:topic name=""/> 最多允许定义2对定界符和占位符,比如既支持<%%> ,也支持 #: 作为定界符 支持不同的模版文件名使用不同的定界符配置,如html结尾模版使用<!--: -->作为定界符,java代码模版使用//:作为定界符 Maven <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl</artifactId> <version>3.19.1.RELEASE</version> </dependency> 最新模板性能测试,各个模板引擎均采用最新版本, Score 越大越好 Beetl=Enjoy>Rocker>>Freemarker>>Thymeleaf==Velociy Benchmark Mode Cnt Score Error Units Beetl.benchmark thrpt 5 109547.863 ± 17161.576 ops/s BeetlByte.benchmark thrpt 5 237799.769 ± 5904.514 ops/s Enjoy.benchmark thrpt 5 99695.440 ± 14083.595 ops/s EnjoyByte.benchmark thrpt 5 223874.001 ± 7265.307 ops/s Freemarker.benchmark thrpt 5 41452.634 ± 15917.119 ops/s Handlebars.benchmark thrpt 5 40360.198 ± 24345.048 ops/s Rocker.benchmark thrpt 5 63657.017 ± 4653.265 ops/s Thymeleaf.benchmark thrpt 5 6457.169 ± 272.613 ops/s Velocity.benchmark thrpt 5 8024.042 ± 2097.396 ops/s 最新脚本引擎性能测试,Score 越大越好 Liquor>>WastEl>JfireEL=Spel>> Aviator=Beetl=Jexl3 >>Mvel=Groovy>>Nashorn Benchmark Mode Cnt Score Error Units Aviator.forExpresss thrpt 5 452423.525 ± 98409.357 ops/s Aviator.ifExpresss thrpt 5 4537367.630 ± 64633.119 ops/s Aviator.simpleExpress thrpt 5 3836403.575 ± 31114.019 ops/s Beetl.forExpresss thrpt 5 1526847.329 ± 265889.574 ops/s Beetl.ifExpresss thrpt 5 4423805.098 ± 1124023.073 ops/s Beetl.reflect thrpt 5 70820.070 ± 97197.223 ops/s Beetl.simpleExpress thrpt 5 4668751.853 ± 242267.492 ops/s Groovy.ifExpresss thrpt 5 138120.419 ± 3309.883 ops/s Groovy.simpleExpress thrpt 5 143464.468 ± 4109.476 ops/s Jexl3.forExpresss thrpt 5 778238.519 ± 37223.120 ops/s Jexl3.ifExpresss thrpt 5 4546708.051 ± 102121.733 ops/s Jexl3.simpleExpress thrpt 5 3959981.088 ± 104018.551 ops/s JfireEL.ifExpresss thrpt 5 28492758.519 ± 1255731.601 ops/s JfireEL.simpleExpress thrpt 5 20056530.964 ± 180910.226 ops/s Liquor.forExpresss thrpt 5 153428936.910 ± 1546258.435 ops/s Liquor.ifExpresss thrpt 5 164543228.416 ± 5095296.054 ops/s Liquor.simpleExpress thrpt 5 146376926.076 ± 4291072.121 ops/s Mvel.forExpresss thrpt 5 12189.900 ± 338.097 ops/s Mvel.ifExpresss thrpt 5 221874.548 ± 37709.654 ops/s Mvel.simpleExpress thrpt 5 322864.761 ± 6554.101 ops/s Spel.ifExpresss thrpt 5 18967054.667 ± 443073.976 ops/s Spel.simpleExpress thrpt 5 18319163.907 ± 627641.759 ops/s WastEl.ifExpresss thrpt 5 43778985.720 ± 502399.670 ops/s WastEl.simpleExpress thrpt 5

优秀的个人博客,低调大师

【BegCode,来自 JHipster 的国产化落地!】

一、BegCode是什么? BegCode是基于JHipster,同时又对前端和核心代码模板进行增强了的一个代码生成工具,该工具是为了解决快速产品开发和推广JHipster理念诞生的。 JHipster应用本身支持很多扩展方式,如BluePrint的方式,利用JHipster核心功能的同时,又可以增加扩展。但BegCode没有使用BluePrint的方式,主要原因是BegCode对一些底层代码进行了改进,无法在BluePrint中达到目的。 二、BegCode亮点 BegCode这些亮点,结合了大量的JHipster爱好者期望并在在长期的实践中总结出来的,让JHipster离我们开发目标更近一步。 1.ORM框架增加Mybatis支持 这一块,不是简单的增加Mybatis本身的支持,还是多方调研,组合了Mybatis-Plus和Diboot-core两个技术框架。 其中Mybatis-Plus简化了Mybatis下的开发,又做了很多动态的查询功能增强,是Mybatis下选择比较多的一种方案。但Mybatis-Plus和Jpa比较,缺失了关联关系的自动化处理。而Diboot-core在这一方面,有自己的优势,是一个不错的选择,二都相结合,在关系处理上又增强了一步,同时这些理念与JHipster的处理方案又比较契合。 2.前端增加Ant-Design-Vue组件库 国内对于Vue.js还是比较喜欢的。但JHipster官方提供的前端效果和功能,不太适合国内一些应用的开发,尤其是缺少了Admin管理平台的部分。 Ant-Design-Vue的组件库受到了Ant Design的影响,具有类似的设计语言和风格,提供了丰富的UI组件来满足各种应用的需求。它还提供了灵活的主题定制和国际化支持。Ant-Design-Vue是一个非常受欢迎的UI组件库,在Vue.js开发社区中被广泛使用。 我们也看到在Ant-Design-Vue组件应用方面,Vben Admin脚手架和Jeecg Boot都做的非常好,相信很多人也有过应用。 基于以上情况,增加了Vben为基础的Admin管理页面的内容并对相应的功能进行了整合,包括用户、角色、菜单、日志、数据字典、定时任务等等。 3.增加更丰富的JDL注解 JHipster基于JDL的注解,是一个非常好用的功能,也是BluePrint方式可定制的一块。丰富的注解,为代码生成增加了很多的可能性。 BegCode在JHipster增加了11个Entity注解,10个Field注解,13个Relationship注解选项。大大增强了生成代码的控制功能。 4.丰富Java的后端接口功能 传统的代码生成工具,包括JHipster在内,针对后端接口的生成方面,除了基本的CURD功能外,增加的不多。 BegCode在JHipster的基础上增加统计汇总接口、关联关系处理接口、排序操作接口,同时增强了多条件查询的能力,丰富了修改信息接口的处理方式。 5.强化生成代码与手工代码的融合 一直以来生成代码与手写代码整合都是一个问题,BegCode在Java方面通过继承来解决用户手写代码被覆盖的问题,在前端方面,通过配置与页面控制分离的方式解决代码覆盖的问题。同时为了更好用户体验,可通过页面注释去定义,这个文件本身是否允许生成器生成的内容将其覆盖。 这些优化,都提高了用户的体验,提高了开发效率,随时生成代码,随时修改代码,让代码生成器总能发挥作用,而不是生成一次后再也不敢使用生成器来自动化生成代码。 6.对JHipster功能的改进 JHipster做为一个生成器工具,其技术和理念非常棒,但内置的业务功能有限,国内用户更喜欢集成更多开箱即用的功能。 BegCode对JHipster内置的用户、权限进行了增强,更符合产品实际需求。 同时增加菜单管理、部门管理、文件上传、短信发送、操作日志、编辑生成、通知公告等功能,而这些功能也是通过jdl进行定义的,BegCode在生成基础代码后,自动生成一次上述功能的代码。如果用户对内置的jdl进行了修改,还可以通过命令行或修改参数的方式让BegCode重新生成上述功能相关的代码。 三、效果展示 1.登录页面 2.默认首页 3.用户列表 4.菜单列表 5.角色列表 6.数据字典 7.短信服务商配置 8.通知公告 9.图片上传 10.消息查看 11.操作日志 12.接口说明 13.图标选择参考 四、使用步骤 1.全局安装generator-begcode npm install -g generator-begcode 2.创建项目目录并在项目目录下执行命令begcode begcode 上述截图表示已经正常启动 3.配置选项 根据系统的提示完成相关的选项。不太了解的选项使用默认值 4.代码生成 随着屏幕的不断滚动,你想要的代码已经生成了 5.启动系统 在全部文件生成后系统会提示如何使用: 启动后端,使用./mvnw启动前端,使用pnpm start 6.进入系统 后端启动完成: 前端启动完成: 现在可以通过http://localhost:3100/进行系统体验了。 源代码参考地址:https://github.com/begcode/monolith-mybatis-antdv 总结 以上内容简单介绍了一下BegCode对JHipster的增强,以及如何更适合国内的开发者,从而进一步提高开发效率。后续有机会再介绍如何快速定义JDL并生成代码。

优秀的个人博客,低调大师

国产 C++ web 框架 paozhu 1.2.0 发布

经过两周不停修改和添加了几个功能,目前入门和友好开箱即用 C++ web 框架 目前代码有几万行,还在不断优化中,集成了Webserver、ORM、WebSocket支持HTTP/1 HTTP/2 优化http2执行代码,大文件专门使用线程下载,方便控制流量。 添加内存缓存session 添加框架缓存对象 添加多目录业务代码注解 添加静态文件压缩后缓存 添加业务代码发起定时执行业务 添加ORM事务处理 添加ORM结果缓存 大量bug修改和代码优化 更多详情可以访问官方 https://github.com/hggq/paozhu 使用例子: std::string testmysqlconnect(std::shared_ptr<httppeer> peer) { httppeer &client = peer->getpeer(); client << "hello world! testmysqlconnect "; client << client.get_hosturl(); client<<"<p><a href=\""<<client.get_hosturl()<<"/showcookie\">show</a></p>"; auto users = orm::cms::User(); users.where("name","admin").limit(1).fetch(); try { client<<"<p>sql result</p>"; // view orm create sql client<<"<p>sql:"<<users.sqlstring<<"</p>"; if (users.getUserid() > 0) { // save session,other page get int userid= client.session["userid"].to_int(); client.session["aaa"] = users.getUserid(); client.save_session(); client<<"<p>found:"<<users.data.name<<"</p>"; return ""; } else { return ""; } } catch (std::exception &e) { client << "<p>" << e.what() << "</p>"; return ""; } return ""; }

优秀的个人博客,低调大师

国产

Solon 是一个高效的 Java 应用开发框架:更快、更小、更简单。它不是 Spring,没有用 Servlet,也无关 JavaEE;它也是一个新兴独立的开放生态。主框架仅 0.1 MB。 150来个生态插件,覆盖各种不同的应用开发场景: 相对于 Spring Boot 和 Spring Cloud 的项目: 启动快 5 ~ 10 倍。 (更快) qps 高 2~ 3 倍。 (更高) 运行时内存节省 1/3 ~ 1/2。 (更少) 打包可以缩小到 1/2 ~ 1/10;比如,300Mb 的变成了 23Mb。 (更小) 同时支持 jdk8, jdk11, jdk17, jdk19。 似曾相似的体验,入门更简单,迁移很方便: @Controller public class App { public static void main(String[] args) { Solon.start(App.class, args, app->{ //手写模式 app.get("/", ctx -> ctx.outputAsJson("{message:'Hello world!'}")) }); } //注解模式 @Get @Socket @Mapping("/hello") public String hello(String name) { return String.format("Hello %s!", name); } } 入门探索视频(用户录制): 本次更新: 新增 solon.health.detector 插件 新增 activemq-solon-cloud-plugin 插件 新增 solon.logging.log4j2(复制于 log4j2-solon-plugin) 新增 solon.logging.logback(复制于 logback-solon-plugin) 插件 beetlsql-solon-plugin 升级 beetlsql 为 3.20.0 插件 sqltoy-solon-plugin 升级 sqltoy 为 5.2.32 插件 dbvisitor-solon-plugin 升级 dbvisitor 为 5.2.1 插件 sa-token-solon-plugin 添加 SaJsonTemplate 实现类 增加 @Condition 注解,提供Com类与Bean函数的过滤支持!!! 增加 AppPrestopEndEvent,AppPrestopEndEvent 事件!!! 增加 配置元信息 solon-configuration-metadata.json 规范与支持 增加 EventBus.pushTry 接口 增加 solon.view.beetl 对 -debug=1 的支持 增加 solon.view.enjoy 对 -debug=1 的支持 增加 ResourceUtil 工具类,提供资源路径表达式分析能力 增强 detector-solon-plugin 扩展能力 增强 mybatis-solon-plugin 的 typeAliases,typeHandlers,mappers 表达式配置能力 调整 local-solon-cloud-plugin 本地文件路径规范 优化 安全停止与延时的配置(增加新的启动参数:stop.safe,和应用配置:solon.stop.safe) 修复 mybatis-solon-plugin 与 solon-maven-plugin 打包插件的兼容性问题 进一步了解 Solon: 《想法与架构笔记》 《生态预览》 《与 Spring Boot 的区别?》 《与 Spring Cloud 的区别?》 项目仓库: gitee:https://gitee.com/noear/solon github:https://github.com/noear/solon

优秀的个人博客,低调大师

如何看待 国产开源软件 购买 GitHub Star

GitHub (https://github.com) 是全球最大的 男性交友网站 (开源项目托管平台). 一个项目的流行程度通常可以看该项目的 Star (关注数), Star 越多, 说明这个项目越受人们欢迎. 但有时候需要擦亮自己的双眼! 私信 现金红包 今天突然看到 CSDN 给我发来一条私信 CSDN 现金红包, 下图是私信页面. 你点 Star, 我送豪礼 发红包肯定是要点开来看看的: 【你点 Star,我送豪礼】旷视自主研发的工业级深度学习框架——天元 MegEngine 重磅升级!集训练推理一体、全平台高效支持、将动态训练代码转换为静态图,优化训练速度等。 为回馈开发者,只要你点 Star,我就送豪礼!感谢你为中国原创助力,凡 Star 天元 MegEngine 用户有机会获得炫酷天元 MegEngine 纪念 T 恤、CSDN定制键盘托、精美 AI 技术书籍以及100小时在线算力卡,欢迎小伙伴积极参与点赞活动。为中国原创点赞,为天元 MegEngine 点赞! 上图页面链接: https://marketing.csdn.net/p/717176bb3f6d2c9c36610987daf57338 评价 一开始觉得怎么会有人花钱买 GitHub Star 呢, 但仔细想想, 这可能就是有钱人的玩法吧. 项目链接: https://github.com/MegEngine/MegEngine 原文链接: https://goworker.cn/posts/china-opensource-software-buy-github-stars/

优秀的个人博客,低调大师

微软推出 AI Dev Gallery——面向 Windows 11 的本地 AI 开发神器

微软针对 Windows 11 AI+ PC 设备推出了 AI Dev Gallery 功能,帮助开发者在其应用中融入端侧 AI 功能。 该功能已在 GitHub 开源:https://github.com/microsoft/ai-dev-gallery。 AI Dev Gallery 旨在帮助开发人员在其应用中尝试各种模型,根据使用场景整合恰当的 AI 功能。 目前,Windows 11 AI+ PC 设备已支持运行小语言模型(SLM),通过本地调用 AI 模型,响应速度比基于云端的 Copilot 或 ChatGPT 更快。 据了解,AI Dev Gallery 兼容 Windows 10、Windows 11 系统,支持 x64 和 ARM64 架构,为开发者提供超过 25 个示例模型,涵盖文本、图像、代码、音频、视频以及智能控制等多个领域,极大地方便了开发者将 AI 功能集成到应用中。 配置方面,开发者需要至少 16GB 内存和至少 20GB 存储空间来运行 AI Dev Gallery,如果需要处理更密集的 AI 资源,建议配备 8GB 显存以上的显卡。 在图片超分采样测试中,科技媒体 Windows Latest 使用了一台配置较低的虚拟机(4核CPU、4GB RAM),在不到 30 秒的时间内,将图片分辨率从 2318*1225 提升到 9272*4900,内存占用约为 1GB。然而,采样后的文本元素被破坏,导致几乎无法阅读,且预览和保存功能尚不完善。 详情:https://www.windowslatest.com/

优秀的个人博客,低调大师

Serverless 微服务治理神器: 阿里云 SAE 全链路灰度揭秘

作者:丛霄、章进、十眠 微服务架构下的灰度发布 微服务链路的复杂性 微服务典型的业务架构模式具有松耦合,可被独立开发、部署以及扩缩容等特点。在项目初期,整个业务规模较小,整个系统还在有条不稳地设计测试运行,服务间的调用关系也比较明确。随着业务规模逐渐扩大,链路调用关系越来越复杂,整个系统的稳定性变得岌岌可危。 其中生产发布灰度过程作为稳定性中重要的一环而备受关注,复杂的功能要能支持完备的灰度能力。面对复杂的微服务调用链路环境,为保证稳定性,业务的上线前往往需要经过详细的测试和漫长的灰度,很多情况下尽管做了详细的测试灰度,也没法保证某一些用户或场景的 Corner Case 能被完全覆盖。 天下苦灰度久矣 针对单体应用,业界有成熟的金丝雀发布和蓝绿发布的解决方案,能帮助用户做更全面的灰度发布保障,但微服务场景下,往往多个微服务应用都在并行开发、测试、灰度,并且多个业务部分之间并没有直接交集,那就很可能出现某业务出现逻辑改动造成的非预期的影响,或是参数兼容问题,或是整个链路的性能影响。 比如图中所示的业务系统,如果 S1、S5、S7、S11 都发生了变更,其中 S7 服务的逻辑变更可能导致某些场景下请求时长变慢,如果事先没有进行全链路端到端的灰度验证,直接全量更新线上,很可能会影响到用户。 这种全链路端到端的灰度验证能力,是所有微服务系统都应当具备的,也是保证服务稳定性重要的一环。阿里双 11 每年都会进行全链路压测,保证所有业务逻辑端到端的功能和性能都能平稳应对双 11 的流量洪峰。正是这种全链路灰度的能力,让开发和运维人员从繁重和不可控的发布过程中解放出来,是实现持续交付的基础,也是安全生产的重要支撑。 SAE 全链路灰度解决方案 原理介绍 阿里云 Serverless 应用引擎(简称 SAE)通过集成 MSE 微服务治理能力,支持在 SAE 应用无缝使用全链路灰度功能。其中要怎么实现灰度环境的隔离是需要考虑的问题。常见的隔离方式分为物理隔离和逻辑隔离, 物理隔离: 这种方式会搭建一套独立的网络、计算资源环境去部署灰度的服务,常见于企业的测试开发环境,但对于线上灰度的环境,因为两套独立的环境很难完全保持一致,一般灰度环境和线上都会在同一套物理环境中。 物理隔离 逻辑隔离: 基于流量染色和分布式链路追踪技术,流量在微服务分布式环境中流转时,可以识别出灰度的流量,并且根据具体灰度规则做出动态流量路由。这种方式可以在线上环境逻辑隔离出灰度环境,并自动将满足条件的灰度流量引入灰度环境进行验证,帮助开发运维同学实时快速地对线上流量进行精细化全链路控制。 逻辑隔离 全链路灰度中的关键概念。 基线应用:在 SAE 生产环境中的应用,可以称作基线应用,当应用没有对应的灰度版本时,流量会默认路由到基线应用。 灰度应用:SAE 可以基于基线应用手动复制出一个灰度应用,它与基线应用在同一个命名空间,使用同一套应用配置(包括注册中心等),除了计算资源是新建出来的,其他都是复用的基线应用的。 灰度标签:灰度标签用于定义隔离的逻辑灰度环境,平台会自动识别应用的灰度标签,将具有同一灰度标签的应用都划分为同一分组。 泳道:基于灰度标签串联微服务调用链路的流量通道,同一灰度环境,需要设置不同灰度规则,就可以创建多个泳道。 泳道组:泳道的集合,一个泳道组下可以创建多个泳道。不同的泳道组对应不同的灰度环境,可以包含不同的灰度应用。泳道组的作用主要是为了区分不同团队或不同场景。 SAE 上的微服务全链路灰度基于逻辑隔离的原理,通过一键创建与生产环境配置一样的灰度应用,可快速支持用户构建起全链路的灰度场景。如下图所示,在命名空间 prod 下,我们可以搭建起线上灰度的链路,用于实际生产发布时候的灰度验证。而在命名空间 dev,我们也可以利用灰度应用的逻辑隔离能力,搭建多套开发环境,这样其实免去了搭建多个开发空间的资源浪费。 核心特性 SAE 下的全链路灰度围绕具体用户灰度痛点去针对性解决,具有以下核心特性: 全链路灰度支持多重灰度策略并行,满足多种业务灰度场景: 通过创建不同的泳道组,实现不同的灰度规则,比如通过比例灰度,可以将一定比例的流量引入灰度环境;而按内容灰度可以基于 HTTP 请求 Header、Cookie、Query、Body Content 等内容进行识别,如果满足灰度条件,则会将流量自动导入到灰度环境中。 SAE 支持灰度应用的一键创建、启停能力,如果在非灰度状态,可以将灰度应用全部关停,需要再次灰度时,可以将灰度应用重启启动,这样无需用户单独创建灰度隔离环境,大幅降低机器/运维成本。 基于 Java Agent 技术无侵入式支持灰度流量感知与路由, 业务方不需要修改任何一行代码,即可在近 5 年的微服务框架 Spring Boot、Spring Cloud、Dubbo 上直接使用全链路灰度的能力。 全链路灰度和链路可观测相结合, 方便用户灰度过程中观测流量的具体分发情况,这对观察线上灰度情况直观重要。 操作实践 接下来我们介绍下在 SAE 上的使用全链路灰度的操作实践。 操作的链路架构图如下所示:其中调用链路是网关 -> A 应用 -> B 应用 -> C 应用。 步骤一:创建业务基线应用 在 SAE 控制台创建应用 A、B、C 和网关应用,这里用到的是 SpringCloud 网关。 步骤二:创建业务灰度应用 对每个 SAE 的基线应用开启为服务治理。进去应用概览-微服务治理,点击"开启微服务治理"。 基线应用开启微服务治理后,回到应用列表界面,创建灰度应用: 创建灰度应用的界面,这里灰度标签需要自定义:可以根据自己业务场景进行定义,这里比如设置为 g1。然后将灰度应用的镜像替换为您需要灰度发布的代码版本。 步骤三:创建灰度环境泳道组 回到 SAE 控制台的微服务治理-全链路灰度界面,点击创建泳道组,选择 Java 服务网关,泳道组流量入口选择您场景的网关应用,泳道组涉及应用选择需要包括到灰度环境中的应用。 在泳道组中创建泳道:点击创建第一个分流泳道,填写泳道信息,泳道标签可以选择之前选中到灰度环境中的应用所包含的标签。然后配置具体的灰度规则,根据业务具体逻辑,在 Path 处输入要灰度的请求路径。灰度模式可以选择按内容灰度或按流量比例灰度。如果选择内容灰度,还需要设置具体的灰度条件,即满足灰度条件的请求会被路由到灰度环境。 创建完泳道后,就可以发起请求,验证请求打到了灰度环境。如灰度规则所设置的,其中只有满足 Header 中包含 gray = gray 的请求才会落入灰度环境。 #测试命令 curl -H "gray:gray" 39.107.xxx.xxx:20000/A/a #测试结果 Ag1[172.16.xx.xxx][config=base] -> 40ms -> B[172.16.xx.xxx] -> 17ms -> Cg1[172.16.xx.xxx]% ➜ 如下图所示,可见灰度规则是生效的。我们进一步点开流量详细,可以看到灰度标上的流量数据,便于在实际线上进行灰度操作时观察灰度的走向。 SAE 微服务治理未来展望 SAE 通过与 MSE 进行深度集成,在 Serverless 场景下为用户提供了使用微服务治理能力的最短路径。全链路灰度作为其中的重磅功能,后续还将在更多的灰度发布能力场景化集成,流量可观测等方向为用户提供更完备的应用变更体验。此外,SAE 还提供无损上下线、限流降级等核心能力,为微服务应用运行稳定性保驾护航。 SAE 会继续致力于为用户提供极简易用、成本低廉、功能强大的 Serverless 应用全托管平台:"我们希望让用户做的更少而收获更多,通过 Serverless 化,深度用云就像用水电煤一样简单"。 询问AI

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册