首先我们来聊一聊传统的桌面软件开发框架。这个类别中包含大家常见的Qt、wxWidgets、GTK、FLTK、Swing和JavaFX。这六个框架有一些共同点:它们的历史都很悠久,使用的开发者也很多,并且相应的社区也很成熟,其中包含了丰富的资料。此外,它们的功能都很强大,有大量成熟的案例,框架也很稳定。
但是它们用到的都是相对来说都是比较成熟的技术,所以跟新兴技术之间还是有所差距,所以使用起来比较困难。
1、Qt
Qt的优点大家都可以在官网上看到,这里不再赘述,其中有一点是Qt对各操作系统都做了很完善的封装,比如网络、文件剪切板等,如果要用系统级的API,Qt可以提供的非常丰富的API。
对于Qt的问题这里介绍一下我的感受,我认为Qt目前的问题是发展方向不太专一,无法提供某些较大的模块,在开发过程中可能会逐渐发现使用的模块不太合适,进而废弃这个模块,包括很多API也是这样,我之前用过的Qtscript现在就已经被标记为废弃了。
2、GTK
GTK框架比较偏Linux,在Linux中有很多桌面应用都是用GTK开发的,在Windows下GTK相对较少,并且在Windows系统下的静态链接也是比较难的,甚至搭环境都比在Linux系统下要难得多。
3、FLTK
FLTK框架是C++之父推荐使用的,它就是一个非常轻量的GUI框架,但是轻量意味着功能是不足的,它的功能比较少,几乎不做系统API的封装,大部分都要开发人员自己用C++编写。这样导致开发人员在每个平台上都要重新编写,比如要开放一个跨平台的图片应用,那么在Windows下调用一些系统级的API进行实现,在Mac下可能又要实现一遍。
4、wxWidgets
wxWidgets跟前面3个框架有所区别,它是基于操作系统的API来做桌面应用的,也就是说,在Windows下开发一个桌面应用时,看起来就像是传统的Windows桌面软件的风格,在Mac下则是Mac的风格,而前面三个都有自己的自绘引擎。
也就是说,在前面三个框架中做一个按钮,不管用什么样的绘制方式,在三个平台下表现都是一致的,但是wxWidgets在三个平台上都是按照三个平台自己的API来绘制这个按钮的。wxWidgets提供了非常多的操作系统的API,并且可以做到静态链接,但小问题比较多。
5、Swing/JavaFX
Swing/JavaFX是基于Java的技术栈来做桌面应用的,因为要依赖JVM,所以系统API比较多,但性能会一般,这两个框架可能相对来说用得少一些。
如果大家在这几个桌面软件框架当中做选择的话,我个人推荐还是用Qt。
刚才我们说的一些框架可能用的技术比较陈旧,大家开发起来比较麻烦。新兴的框架,比如微软的MAUI、谷歌的FlutterDesktop和JetBrains公司的ComposeMultiplatform,都是采用非常新的技术来做的,开发起来很容易,开发体验也非常好。
但是因为这几个框架都比较新,基本上都是今年发布的正式版(最早是ComposeMultiplatform发布的,然后依次是lutterDesktop和MAUI),所以社区相对来说不如前面几个框架成熟,资料和成功案例也相对来说少一些。
1、MAUI
MAUI是用XAML是写界面和逻辑的,大家如果用WPF写过软件的话,应该会对这项技术很熟悉。MAUI用C#编写业务逻辑,只兼容Windows操作系统和Mac操作系统。MAUI在Linux下是社区提供的一套支持体系,可能会有一些问题。另外,MAUI是依赖.NET框架的,API比较多,并且支持移动端(这三个框架都是支持移动端的,新兴的开发框架都兼容移动端的开发)。
2、FlutterDesktop
FlutterDesktop是使用dart编写界面逻辑的,它的组件比较丰富,并且支持Win10操作系统(之前的操作系统就不太支持了),API是比较少的,需要开发人员自己来写。
3、ComposeMultiplatform
ComposeMultiplatform依赖JVM,是用Kotlin编写逻辑的界面和逻辑的,有消息说将来可能会推出Kotlin/native*,这样就可以不用依赖JVM了,但是这可能还比较遥远的事情。ComposeMultiplatform的组件也是比较丰富的,大家都知道Java社区中有很多框架、模块等都可以使用,并且也是支持应用端的。
在这几类框架里中我推荐大家使用FlutterDesktop,虽然它们都是新兴的框架,所以很难说哪一个将来会更受欢迎,但是根据它们的共同点(技术更现代化、更加易用、资料较少、社区不成熟、成功案例较少、用户较少、不稳定),我还是推荐FlutterDesktop。
基于浏览器的桌面软件开发框架相对较多,比如Electron、NW.js、CEF、Sciter、WebView2、webview和TAURI。其中使用Electron比较多,也已经非常成熟。它们的共同点是它们可以复用浏览器的技术,比如html、JS和CSS等一系列生态中的组件。
除此之外,它们还可以做非常绚丽的界面,因为Web技术发展这么年,CSS、html等在标记和控制界面特性方面的技术都已经非常成熟,不像刚才提到的FLTK要做叠加动画效果都非常困难,如果用这些技术做这些界面会非常从容。但这些框架的功能也是有强有弱。
1、Electron/NW.js
Electron和NW.js这两个框架是非常相似的技术,它们都是把Chromium与Node.js集成到一起,让开发者可以只使用前端技术开发桌面应用。如果要访问系统的API,就用Node.js提供的API,当然也有一些特殊的API,比方创建桌面图标、访问剪切板、控制窗口大小等,是Electron框架本身提供的,而不是Node.js提供的,也不是传统HTML系统提供的,是在其中做了一些附加的操作,当然NW.js也有。
这两个框架的作者都有很深的渊源,这里就不细说了。我个人觉得NW.js实现起来相对来说比较巧妙,对开发者比较友好,而Electron维护更给力,社区也很庞大。
2、CEF/WebView2
CEF和WebView2框架都是直接基于Chromium开发的。CEF的历史比较悠久,而且更灵活,大家可以通过这个框架进行自由的控制,API也更多。
WebView2是微软的短期团队提供的一个框架,这个框架也是直接基于基于Chromium做的封装,它提供了.NET和C++的API,大家可以用.NET、C++或者C#语言去操作这个框架,目前还不支持MAC(将来可能会支持)。
相对来说CEF更像作者个人在维护,WebView2就更像一个团队,但是因为WebView2不开源,所以也没法参与。
3、webview/TAURI
webview和TAURI使用操作系统内配置的浏览器核心,比如应该在Windows下部署,那么就用WebView2;如果在Mac下部署,就用WKWebView;如果在Linux下部署,就用webkitgtk来做渲染,因此这里可能就会有一些兼容性的问题。
在做前端的时候经常会碰到一些兼容性的问题,但是目前来看,因为它们都是比较现代的浏览器核心了,所以这个问题还没有这么明显。另外,TAURI是使Rust开发的,如果要选择这个框架,可能还得熟悉Rust语言。
4、Sciter
Sciter是一个比较特殊的框架,这里把它单列出来,Sciter做了很多的削减,可以把产物的体积缩减到10M以内,前面几种框架基本上只要把浏览器核心分发给用户,即使压缩过后也得60M。
如果大家选择这类框架,我推荐使用Electron/CEF框架。如果团队中没有C++开发人员,或者不易于使用C++进行开发应用,就选择Electron;如果有C++开发人员,而且应用非常注重性能,就选择CEF。
即时渲染相对应用的是保持模式的桌面应用框架,一般做桌面应用都是哪里需要更新,就更新哪里,框架会进行渲染。但是即时渲染是不一样的,它是每刷新一帧,就会把显示的内容都更新一遍,也就是说每一帧都会全部更新一遍。
所以这类框架有一个共同的特点,就是它们要消耗CPU和GPU资源,传统框架的配置都是保持模式,如果不更新是不会做渲染的。另外,这种框架与游戏应用可以无缝对接,但是传统应用案例比较少,小问题比较多,且尚在发展中。
1、DearImGui
即时渲染桌面软件开发框架中,DearImGui比较流行,最近作者在开发Dock模式,估计今年有可能会推出,到时候大家可以去尝试一下。
它的开发方式是比较特别的,就是每个循环都在做渲染。比如使用DearImGui做事件开发时,会将某一个变量设置为true或者false,在这一轮渲染的过程当中是true,在它下一轮渲染过程当中,我发现变成false了,我们就认为触发了某个事件。而不是像web开发领域中,当出现一个event时,另一个组件就可以接收到它。
2、Nuklear
Nuklear是使C语开发的,更贴近C开发者的习惯,户相对DearImGui更少、问题更多。
3、RmIui
RmlUi比较特殊,它不是即时渲染框架,但是却有即时渲染框架的通病,就是用它开发应用之后会持续消耗CPU和GPU资源,它可以使用HTML和CSS描述界面,上手相对比较难,开发非常灵活,界面也很灵活,资源消耗相对更多。
我最近一直在用这个框架,也跟作者进行了深入的交流。这个框架开发出来的应用程序可以做到2M左右,它可以解析你的HTML,做一些非常特殊的效果,比如阴影、渐变之类的动画,但是它很小,不像浏览器一样,即使压缩也得60多兆,这也是它的优势。
这几类框架中我个人推荐RmlUi,如果到作者的项目中进行提问,他基本上隔天就会回复。
在做总结之前,我先简述一下这几个框架的对比。
其实我们在介绍传统的桌面开发框架的时候,Qt和wxWidgets内置的组件也有基于浏览器的,就是QWebEngin和wxWebView,QWebEngin封装的是Chromium的核心,其实与CEF和QWebEngin挺像的,但是很多人在用Qt的时候,是把CEF集成到Qt中,反而不用QWebEngin。
他们坚持的观点就是QWebEngin还不成熟,性能力相对来较弱,不如CEF,但是目前来看,我个人认为,在Qt6.2和Qt6.3之后,QWebEngin的API会更多,应用的需求更容易满足。
wxWebView更像是webview和TAURI,它也是在不同的操作系统上使用操作系统的浏览器核心,这里就不多说了。
再看一下RmlUi和Sciter的对比。RmlUi可以用html和CSS,Sciter也可以用html和CSS,因为Sciter集成了QuickJS,所以它也可以写JS代码(但是也得写C++,因为你不可能不用操作系统的API,但是它的C++可能会比RmlUi的C++代码量要少很多)。两个框架都不支持全部的html和CSS规范。
如果要选一个桌面软件开发框架,应该确认侧重哪方面的能力,我认为有三方面的能力是需要注重的:
另外,桌面软件开发框架各有各的优势,比如软件开发逻辑很复杂,而且要快速地完成,那么BrowserCore可能是一个不错的方式,因为用前端技术来编写速度更快,但是如果软件需要更少的资源消耗和更快的运行速度,那么就需要考虑Native方式。
最后,要做桌面应用开发需要了解一些底层知识,比如多线程、多进程的控制;各种通信协议;志收集;版本控制;设计模式与架构原则;本地数据控制;操作系统。
1、用Electron怎么处理crash?
Electron也有非常多问题,它也会崩溃,并且有崩溃报告的收集方式,收集这些报告之后还要进行分析,但是分析出来的崩溃报告实并不能很明确地反映到底是哪一行代码、哪一段业务出了问题。很多时候崩溃报告中可能更多的是说明一个指针指向的内存出现了问题,这时一种方法是尽量联系用户复现问题;第二种方式是做大量的自动化测试,收窄问题的范围,将其局限在一定的范围内再做精细化处理;第三种方式就是做AB测试。
2、Electron开发的应用安装包太大这个问题有没有好的解决办法。另外,开发者该如何开发Electron应用的守护进程。
至于怎么做守护进程,这个问题现在有两种办法,一种是写一个独立的应用,在Electron启动的时候应用就可以随之启动,然后它守护Electron进程。如果Electron进程崩溃的时候,就由它来启动Electron进程。
另一种方法是分析应用为什么崩溃,是主进程崩溃了,还是渲染的时候崩溃了,你如果主进程崩溃了,尽量还是要找到其崩溃的原因,因为一旦主进程崩溃,那么所有渲染都会失败;如果是渲染进程崩溃了,那么可以在主进程中打开一个其他的进程,来保证将渲染崩溃的通知发送给用户,由用户重启渲染进程,或者自动重启。
选中SpringInitializr->ProjectSdk->Next
最后配置项目的路径即可,点击Next
新建项目的pom.xml文件如下:
目录
步骤一:继承Thread类
步骤二:重写run()
步骤三:Thread类对象执行start()启动线程
步骤一:实现Runable接口
步骤三:Thread类对象处理Runable接口实现类对象,执行start()方法
步骤一:实现callable接口
步骤二;重写call()方法
步骤三:FutureTask对象处理callable接口实现类对象,得到任务对象
步骤四:Thread类对象处理任务对象,执行start()方法
补充:常用API
注意,这个方法是在哪个线程对象中使用,就会返回哪个线程对象。
说明:为了保证线程安全,我们通常采用锁来处理多线程
锁的对象问题:
1、锁对象唯一,比如用一个字符串当锁对象
一个锁锁住了千家万户,锁对象唯一不可取。锁对象唯一任何时刻都只允许一个线程进来,但是有时候我们需要有的线程进来有的不进入共享资源访问。
2、实例方法,使用this作为锁对象
使用this就是把字符串的地方换成this,就不多做概述了,懂得都懂。
3、静态方法,使用字节码(类.Class)作为锁对象
在方法上面加Synshronized关键字
修饰符synchronized返回值类型方法名称(形参列表){操作共享资源的代码}底层原理:如果是实例方法,则会选择使用this作为锁对象,如果是线程里调用静态方法,则使用类名.class作为锁对象。
lock锁更加灵活,可以自定义上锁解锁,只需创建一个Lock锁的对象调用相应方法即可。
线程池就是一个线程复用技术。
我理解的线程池是由核心线程、任务队列、临时线程组成的。
当有新任务到来时,首先会交给核心线程处理,当核心线程处理不过来时,会将任务放入任务队列等待,而当任务队列满了时,这时候会创建临时线程。若果临时线程创建后超过最大线程数,则程序会报错。
方法一:publicstaticExecutorServicenewFixedThreadPool(intnThreads):创建固定线程数量的线程池
方法二:publicstaticExecutorServicenewCachedThreadPool():线程数量随着任务增加而增加
方法三:ublicstaticExecutorServicenewSingleThreadExecutor():创建只有一个线程的线程池对象
方法四:publicstaticScheduledExecutorServicenewScheduledThreadPool(intcorePoolSize):创建定时器类的线程池对象
voidexecute(Runnablecommand):没有返回值,一般用来执行Runnable任务
Future
voidshutdown():等任务执行完毕后关闭线程池
注:在我看来线程池可以接线程对象,因此线程对象既是一个线程对象又是一个任务。
面试题:
1、Executors工具类底层是基于什么方式实现的线程池对象?线程池ExecutorService的实现类:ThreadPoolExecutor
2、Executors是否适合做大型互联网场景的线程池方案?不合适。建议使用ThreadPoolExecutor(第一种创建线程池对象的方式)来指定线程池参数,这样可以明确线程池的运行规则,规避资源耗尽的风险。
创建定时器对象,调用schedule()方法
另:一个进程可以包含多个线程
注意一点,你要用谁去调用这里边的方法,我来告诉你,你要用抢到锁的那个对象去调用这里面的方法,比如说加锁的对象哦对还得提醒一点,你这个方法实在哪里运行调用啊,在锁里面啊混是代码块还是方法lock的,反正你是在锁里,既然在锁里调用这些方法就用锁对象,实例方法你可以用this.方法名,静态方法呢?静态你寻思寻思也白搭呀人家的方法是给噢波基特用的。
线程池在网络通信中的应用,传送门:
选自towardsdatascience
作者:DimitrisPoulopoulos
机器之心编译
编辑:陈萍
微软推出的VSCodePython语言插件Pylance,给Python带来编译语言般的开发支持。对于最近更新的VSCode版本,除了保留Pylance原始特性外,又引入了新特性。
Pylance是微软今年推出的Python语言服务器,可以利用语言服务器协议与VSCode进行通信。Pylance在VSCode中为Python提供了快速、特性丰富的语言支持,并依赖于核心的Python扩展,从而极大地改善了VSCode中的Python体验。
随着本月VSCode的更新,Pylance可以执行用户期待已久的操作,将Python开发体验带到一个新的水平。在本文中,机器学习工程师DimitrisPoulopoulos将为读者介绍Pylance的功能以及在新版VSCode中的可用最新特性。
Pythonstub文件
Pylance利用类型stub文件(.pyi文件)和惰性类型推断为使用者提供了高效的开发体验。
什么是stub文件呢?
Stub文件为Python模块提供类型提示信息。完整的官方信息可以在PEP-484中的Stub-files章节中找到。例如,下面的Python函数存在于my_function.py模块:
defadd(a,b):returna+b我们也可以创建一个新的stub文件my_function.pyi,以提供类型提示:
defadd(a:int,b:int)->int:...注意:在stub文件中,定义函数末尾的「...」是语法的一部分。
然而,我们可以在Python模块中插入类型提示,而不需要创建新的stub文件,如下代码所示
defadd(a:int,b:int)->int:returna+b问题来了:我们为什么要使用stub文件呢?这里有几个原因:例如保持.py文件向后兼容;向现有代码库中提供类型提示,并希望尽量减少源代码本身的更改等等。
讲完stub文件优点,我们再回到Pylance本身。stub文件通过丰富的类型信息增强了PythonIntelliSense体验,帮助开发者更快地编写代码。更重要的是,Pylance已经为流行模块提供了一个stub集合,其内置的stub库提供精确的类型检查以及快速自动补全功能。
Pylance特性展示
和其他Python语言服务器一样,Pylance也是围绕提升开发效率和体验进行优化。Pylance特性有很多,下面介绍几个比较重要的特性:
类型信息显示:当你把鼠标悬浮在对应的函数上方时,就可以显示对应的函数文档。
自动导入功能:在使用Pycharm的时候,当用到某个包或者模块时,可以通过快捷键Alt+Enter快速导入对应的模块。通过Pylance也可以实现相同的功能,现在我们可以自动导入已经安装好的标准库模块。
类型检查:类型检查可以帮助我们验证参数在传入函数执行前类型是否正确。Pylance中类型检查默认是关闭的,需要在设置中启动,操作方法为:设置「python.analysis.typeCheckingMode」为「basic」或者是「strict」。
VSCode更新引入了Pylance新特性
最近,VSCode更新引入了几个新的Pylance特性,其中代码提取和PylanceInsiders程序非常重要。
代码提取:我们可以通过单击来提取代码中的方法和变量。
PylanceInsiders:PylanceInsiders程序,它提供了对新语言服务器特性和改进的早期访问。要启用insiders,请设置「pylance.insidersChannel」:「daily」。