hexo-start
摘要内容……
摘要内容……
经常刷 LeetCode 的读者肯定知道鼎鼎有名的 twoSum
问题,我们的旧文 Two Sum 问题的核心思想 对 twoSum
的几个变种做了解析。
但是除了 twoSum
问题,LeetCode 上面还有 3Sum
,4Sum
问题,我估计以后出个 5Sum
,6Sum
也不是不可能。
那么,对于这种问题有没有什么好办法用套路解决呢?本文就由浅入深,层层推进,用一个函数来解决所有 nSum
类型的问题。
[leetcode1](1. 两数之和 - 力扣(LeetCode) (leetcode-cn.com))
力扣上的 twoSum 问题,题目要求返回的是索引,这里我来编一道 twoSum 题目,不要返回索引,返回元素的值:
如果假设输入一个数组 nums
和一个目标和 target
,请你返回 nums
中能够凑出 target
的两个元素的值,比如输入 nums = [5,3,1,6], target = 9
,那么算法返回两个元素 [3,6]
。可以假设只有且仅有一对儿元素可以凑出 target
。
我们可以先对 nums
排序,然后利用前文「双指针技巧汇总」写过的左右双指针技巧,从两端相向而行就行了:
1 | vector<int> twoSum(vector<int>& nums, int target) { |
这样就可以解决这个问题,不过我们要继续魔改题目,把这个题目变得更泛化,更困难一点:
nums
中可能有多对儿元素之和都等于 target
,请你的算法返回所有和为 target
的元素对儿,其中不能出现重复。
函数签名如下:
1 | vector<vector<int>> twoSumTarget(vector<int>& nums, int target); |
比如说输入为 nums = [1,3,1,2,2,3], target = 4
,那么算法返回的结果就是:[[1,3],[2,2]]
。
对于修改后的问题,关键难点是现在可能有多个和为 target
的数对儿,还不能重复,比如上述例子中 [1,3]
和 [3,1]
就算重复,只能算一次。
首先,基本思路肯定还是排序加双指针:
1 | vector<vector<int>> twoSumTarget(vector<int>& nums, int target { |
但是,这样实现会造成重复的结果,比如说 nums = [1,1,1,2,2,3,3], target = 4
,得到的结果中 [1,3]
肯定会重复。
出问题的地方在于 sum == target
条件的 if 分支,当给 res
加入一次结果后,lo
和 hi
不应该改变 1 的同时,还应该跳过所有重复的元素:
1 | while (lo < hi) { |
这样就可以保证一个答案只被添加一次,重复的结果都会被跳过,可以得到正确的答案。不过,受这个思路的启发,其实前两个 if 分支也是可以做一点效率优化,跳过相同的元素:
1 | vector<vector<int>> twoSumTarget(vector<int>& nums, int target) { |
这样,一个通用化的 twoSum
函数就写出来了,请确保你理解了该算法的逻辑,我们后面解决 3Sum
和 4Sum
的时候会复用这个函数。
这个函数的时间复杂度非常容易看出来,双指针操作的部分虽然有那么多 while 循环,但是时间复杂度还是 O(N)
,而排序的时间复杂度是 O(NlogN)
,所以这个函数的时间复杂度是 O(NlogN)
。
这是力扣第 15 题「三数之和」:
题目就是让我们找 nums
中和为 0 的三个元素,返回所有可能的三元组(triple),函数签名如下:
1 | vector<vector<int>> threeSum(vector<int>& nums); |
这样,我们再泛化一下题目,不要光和为 0 的三元组了,计算和为 target
的三元组吧,同上面的 twoSum
一样,也不允许重复的结果:
1 | vector<vector<int>> threeSum(vector<int>& nums) { |
这个问题怎么解决呢?很简单,穷举呗。现在我们想找和为 target
的三个数字,那么对于第一个数字,可能是什么?nums
中的每一个元素 nums[i]
都有可能!
那么,确定了第一个数字之后,剩下的两个数字可以是什么呢?其实就是和为 target - nums[i]
的两个数字呗,那不就是 twoSum
函数解决的问题么🤔
可以直接写代码了,需要把 twoSum
函数稍作修改即可复用:
1 | /* 从 nums[start] 开始,计算有序数组 |
需要注意的是,类似 twoSum
,3Sum
的结果也可能重复,比如输入是 nums = [1,1,1,2,3], target = 6
,结果就会重复。
关键点在于,不能让第一个数重复,至于后面的两个数,我们复用的 twoSum
函数会保证它们不重复。所以代码中必须用一个 while 循环来保证 3Sum
中第一个元素不重复。
至此,3Sum
问题就解决了,时间复杂度不难算,排序的复杂度为 O(NlogN)
,twoSumTarget
函数中的双指针操作为 O(N)
,threeSumTarget
函数在 for 循环中调用 twoSumTarget
所以总的时间复杂度就是 O(NlogN + N^2) = O(N^2)
。
这是力扣第 18 题「四数之和」:
函数签名如下:
1 | vector<vector<int>> fourSum(vector<int>& nums, int target); |
都到这份上了,4Sum
完全就可以用相同的思路:穷举第一个数字,然后调用 3Sum
函数计算剩下三个数,最后组合出和为 target
的四元组。
1 | vector<vector<int>> fourSum(vector<int>& nums, int target) { |
这样,按照相同的套路,4Sum
问题就解决了,时间复杂度的分析和之前类似,for 循环中调用了 threeSumTarget
函数,所以总的时间复杂度就是 O(N^3)
。
在 LeetCode 上,4Sum
就到头了,但是回想刚才写 3Sum
和 4Sum
的过程,实际上是遵循相同的模式的。我相信你只要稍微修改一下 4Sum
的函数就可以复用并解决 5Sum
问题,然后解决 6Sum
问题……
那么,如果我让你求 100Sum
问题,怎么办呢?其实我们可以观察上面这些解法,统一出一个 nSum
函数:
1 | /* 注意:调用这个函数之前一定要先给 nums 排序 */ |
嗯,看起来很长,实际上就是把之前的题目解法合并起来了,n == 2
时是 twoSum
的双指针解法,n > 2
时就是穷举第一个数字,然后递归调用计算 (n-1)Sum
,组装答案。
需要注意的是,调用这个 nSum
函数之前一定要先给 nums
数组排序,因为 nSum
是一个递归函数,如果在 nSum
函数里调用排序函数,那么每次递归都会进行没有必要的排序,效率会非常低。
比如说现在我们写 LeetCode 上的 4Sum
问题:
1 | vector<vector<int>> fourSum(vector<int>& nums, int target) { |
再比如 LeetCode 的 3Sum
问题,找 target == 0
的三元组:
1 | vector<vector<int>> threeSum(vector<int>& nums) { |
那么,如果让你计算 100Sum
问题,直接调用这个函数就完事儿了。
记得高中时特喜欢看《名侦探柯南》,剧情对逻辑能力有一定考验,看起来还是比较烧脑的。
所以那时堂主就有意识不断提升自己的逻辑思维能力,也发现了自己因为该项能力不足而产生的各种问题。
每天那么多事情,还是不知道从哪里做起,总是手忙脚乱……
公开讲话或展示报告,总表达不出重点,心里特着急……
看书写文也是随心情,真正下笔时,不知道从何下手……
堂主,我有一个疑问想求解答。像《金字塔原理》等这类书籍,看完后感觉想要真正融入实践去运用好难,不知道这是认知问题还是思维习惯的培养或者其他原因呢?
这本书堂主也看了几遍,最后发现,逻辑思维不好,既是思维固化的原因,也是认知以及方法论的问题。
所以,今天给大家分享的这篇文章,能够一定意义上帮助大家解决留言类似问题。
相信我,如果你借鉴文章中的一些方法,逻辑思维会有巨大提升!
01.
沟通框架法
日常沟通中,没有逻辑框架的表达差别,是很明显的。
比如你通知同事开会:
逻辑不清者:
下午3点开会,记得提前10分钟过来开空调到25°,在桌子上摆上景田,总监爱喝;
他下午要来总结月度目标,顺便帮我通知下其他人,在110会议室~
很可能到时候同事忘记通知其他人,晚到了半个小时,你也喝不上怡宝,被总监请去喝茶了……
有逻辑者:
今天下午3点,总监要来110会议室开月会,辛苦你通知下其他人;
再麻烦提前10分钟过来开好25°的空调,摆上总监爱喝的怡宝。
先说总体事项,再说细节,最后搭上同事个人收益。
下面堂主分享3个框架模型,可以作为形成你个人方法论的参考。
1、 工作沟通:STAR模型
这个模型能帮你轻松通过面试、工作汇报。
我们最大的问题,就是不懂如何有逻辑地向领导或面试官,展示自己的优势,以及工作的成果。
明明打好了满肚子的腹稿,一出口就变成了:“额……额……”
这种情况面试官内心独白估计是赶紧打发回去吧。
掌握好STAR模型的工作沟通方法,让你能够非常清楚自己需要表达什么。
S——情境(situation),事情是在什么情况发生的?
T——目标(target),你是如何明确自己的任务?
A——**行动(action)**,根据目标采取什么行动?
R——**结果(result)**,最后结果如何,个人有什么收获?
不需太啰嗦,每个点说1-2句即可。
举个面试例子,一个想去新媒体公司的大学生,自我介绍时可以这么说:
在校期间我是学校官方微信号的负责人(s);
我的主要任务是官方校园动态、和学生有趣槽点的推送,以及指导新社员(T);
在2年内我参考了近100个高校官微的运营模式,同时业余参加新媒体课程、请教老师(A);
最后总结了一套自己的写作模式和运营模式,经过验证,官微阅读量从6k上升到1.5w,自己拥有了5k粉丝量的个人账号。(R)
不到一分钟的时间,有条理地表达自己的工作成果,充分展现自己的个人能力。
2、 情感沟通:FOSSA模型
很多争吵都是因为情绪表达不到位,加剧了矛盾火力,越吵越凶。之后即便你有情绪,那么不妨在沟通之前,想想下面几个问题。
另外在我们的人生道路上,永远不要发生无谓的冲突,你要清楚自己是一块宝石,犯不着和石头硬碰硬。
如果碰到烂人尽量大事化小,小事化了,实在触及到底线,再适当予以反击。
3、 阅读拆解:SQ3R模型
有逻辑地进行阅读,能大大提高你的读书吸收效率。
大多人都是拿本书就看,看完一头雾水,讨论起书中内容开始蒙了。
用SQ3R阅读模型框架,能轻松帮你理清思路,用最短的时间得到更多的知识点。
同时阅读笔记很重要,绝对不只是单纯的“ctrl+v”、“ctrl+c”****,没经过思考的笔记,就算记得又臭又长也毫无用处,因为你根本不会去看。
02.
思维清单法
这是逆转你思考方式的方法,对生活工作都特别有帮助。
逻辑性强的人,善于解构任务,化繁为简,剔除无用信息, 能用更短的时间解决更多的事情。
这就是锻炼逻辑思维的好处和目的——替自己和别人省出更多时间,而时间就是金钱。
刚刚毕业时候做公司报告,我很认真写了30-50来张ppt。
结果当天被领导点名批评:废话连篇,乱七八糟,抓不住重点。
最后参考了一个思考顺序清单,通过大量练习,之后每次总结都基本能够得到领导的认可。
这个思维清单中和了「演绎推理法」和「归纳整理法」****,能让你从时间、空间、事情重要程度等方面,进行全方位思考。
你遇到的每个难题,只要按照以下清单顺序考虑,都能迎刃而解,效果真不是吹的,谁用谁知道!
第一步:结论先行
第二步:分析情况
第三步:解决方法
第四步:时间规划
第五步:开始行动
举个应用例子,方便大家理解具体的操作方法:
你是新媒体公司的实习生, 现在要进行转正答辩,怎么有逻辑地表达自己3个月的工作成果?
第一步:结论先行
先把3个月的工作成果展示出来,让领导看到完成值。
这是特别重要的一点!不管报告还是沟通,先说结论能节省所有人的时间。
第二步:分析情况
列出影响数据的分析原因、工作亮点与不足、工作收获等……
这部分要遵循总分总原则,由上到下层层递进,带着“为什么会这样、如何改善”的思维,去剖析出每个问题。
第三步:确定方法
针对所有问题,用归纳法整理出“时间、空间”所有解决的方法、再用演绎法写出,每个能具体实施的方案。
比如:家离公司太远,通勤时间过长,学习时间过少。
时间上:每天提前半小时起床、或在上班途中学习、增大工作密度。
空间上:搬家,缩短空间距离。
第四步:时间规划
这一步,要根据自己的解决方法,和事情的重要程度,列成一个工作规划表:
先做什么、再做什么、之后做什么、最后做什么?
第五步:开始行动
如果不行动,上面所有的逻辑推理都是在纸上谈兵,只会让我们的思维认知停留在原地,毫无长进,所以,行动才是关键啊!
03.
持续积累法
接下来这句话,可能会让你恍然大悟!
其实很多时候,不是因为我们逻辑不好,而是我们的知识存量是有限!了解的事情太少,导致逻辑联系不起来。
想升级自己的逻辑思维,最根本的方法,就是扩大自己的知识储备。
接下来堂主就分享3种提升思维的认知渠道,就算只坚持10天半个月,也有很大的成效!
1. 尝试演讲,形成应激反应
能够参加演讲、辩论类的人,逻辑思维都会比一般人好很多,所以模仿优秀的人,也是很好的提升方法。
长期坚持下来,你就会遇事不慌,面对一切新挑战、繁琐工作,都能迅速上手~
同时,生活中也要抓住一切机会,锻炼自己的表达能力,这里分享2个小细节:
1) 线上工作沟通时,需回复较长信息,可以刻意练习这个回复结构,来表达自己的观点:
第一、第二、第三……
2) 与人沟通时,也同样刻意练习:我有三个方面要说,123……
咳咳,这里我也有三句话要说, 大家注意啦!
第一,能坚持看到这里的同学好优秀!文章快结束了,再坚持坚持哦~
第二,如果喜欢这篇文章的话,记得保存下来,方便以后查看哦~
第三,答应我, 看完去输出个思维导图大纲,这是你提高逻辑思维第一步~
2.看思辨类节目,代入正确角色
这时有人要问了:堂主,我也没少看节目啊,我还是没长进啊。
为什么会这样?
因为你自动代入了观众角色啊,本来正方立场,结果反方一发言,你就觉得:啊好对好对,我怎么没想到!这时正方又把你拽回来:是啊是啊,就是这样!老铁懂我!
一直被别人牵着鼻子走,要是你在现场,估计投票键都会被你摁烂了。
代入选手角色, 选正方,就坚定做正方,选反方,就坚定做反方。
对方一发言,不是想着对对对,而是:不对,他有漏洞,忽略了客观角度,巴拉巴拉。队友发言,也不急着赞同,同样分析他的逻辑表达方式。
吃透这边的论证后,再换个立场训练,你会发现一期节目你得看3456遍,你才能彻底了解辩题的所有角度,客观地表达最正确的想法。
3. 读思辨类书籍,繁殖知识量
这个重要性,就不用我再多说啦,只有看更专业的书籍,才能更全面了解思维模型,废话不多说,直接上推荐书籍。
1)入门书籍,引起你纠正思维的兴趣:
小学生也可以读的启蒙思维书籍,说一个道理搭配几个生活事例, 特别简单粗暴。
很喜欢这句话:人是生而自由的,却无往不在枷锁之中。
完美不枯燥的一本书,书不厚但很耐读,干货特别多,故事很有趣。
从5个方面来帮助你形成自己的方法论:定义问题-分析问题-由谁解决问题-问题来自哪里-如何做一个问题解决者。
2)进阶书籍,系统学习深度思考
前身是《学会提问》,我们最缺的就是批判性思维,这本是入门最佳之选,算是理性“杠精”指南,让你学会理智独立思考,就算说不过别人,也别被别人骗。
读完可以立马用的干货书,书评有句话令人深思:“只要你有批判性思维你就能批判自己的思维”。
最后,送大家两句话,一起共勉:
1、 无论一个问题多么复杂,如果能以正确的方式去看待,它都会变得简单起来。
2、 花半秒钟就看透事物本质的人,和花一辈子都看不清事物本质的人,注定是截然不同的命运。
愿你能养成善于思考的习惯,生活中增加思考频次,慢慢掌握洞察事情本事的能力,点个「在看」,一起成为逻辑大神吧~
免费版本不支持导出excel格式,所以得想办法使用ue版本。
官方安装包下载地址 https://downloads.dbeaver.net/ultimate/23.3.0/dbeaver-ue-23.3.0-macos-x86_64.dmg
链接: https://pan.baidu.com/s/1xWo75x9HiWDyQajGY9TUKw?pwd=a16r 提取码: a16r,下载并解压,放到一个专门的目录,下面会用到
在应用程序里,右键显示包内容,找到dbeaver.ini (/Applications/DBeaverUltimate.app/Contents/Eclipse/dbeaver.ini)
找到 -vm,替换原始java路径,修改如下
1 | -vm |
然后在文件末尾添加如下两行
1 | -Dlm.debug.mode=true |
1 | # dbeaver start |
打开安装好的DBeaver UE,如果闪退或提示已损坏,请自行搜索解决办法。打开后,会提示让你输入注册码,输入下面的注册码即可
1 | aYhAFjjtp3uQZmeLzF3S4H6eTbOgmru0jxYErPCvgmkhkn0D8N2yY6ULK8oT3fnpoEu7GPny7csN |
如无意外,目前应该已经破解成功了。
知乎上有人提问:做个很小众的应用就可以月入数万,为什么多数程序员都不做个人开发?
有个匿名的用户回答的挺好的,详细讲述了自己独立开发软件转起的经历,以下是正文内容:
我要匿名了,因为要说真话了。
我写的其中一个软件(后续以“电脑工具软件”称呼),电脑端的,月入在2.5~3万,规模还在扩大。
先说一下过程吧,提到的各种编程技术对于我后期做成这个小众应用都很重要。
12年毕业,在上海工作两年期间主要工作语言是C语言、RedHat服务器、Oracle数据库、Delphi7、C#的Winform技术,利用加班时间,我简单学过QT技术。
14年7月起,在郑州工作过一年,主要是C语言以及各种网络协议数据抓取、分析审计。
15年清明节,来深圳创业,直到18年7月份因团队变故离开,在此期间我担任公司CTO,学会了Java 、Mysql、Redis、CentOS、微信支付宝支付流程等。
18年到19年清明节前,我去河北,在此期间我学会了android应用开发(原生开发),但是没挣到钱。
19年初,春节过后,闲的,花了10天吧,完成了我要说的这个电脑工具软件软件的第一个版本,尽管很简陋,bug很多。
由于在河北没挣到钱,我又于19年清明节那天,回到了深圳,又加入了原来的那个团队。公司被他 们搞的一团遭,都破产了,我回来后,我们又接了个项目从头开始。
19年特别忙,我也没空再维护我那个软件。对于公司项目,我又学会了开发微信小程序,公众号,uniapp等技术。
20年,做了一个智能软件项目,我又学会了iOS开发(用的是object-c 和 uniapp 混合技术)
到此,根据我的熟练程度。
编程语言我掌握了:Java、JavaScript、C#、Python、Nodejs、go、Html、CSS、c、delphi数据库:mysql、Oracle、MangoDB、Redis
客户端:桌面网页端、Androdi端、windows电脑桌面客户端、iOS应用、微信小程序、公众号
服务器端:宝塔、Java的Springboot系列开发
总的来看,除过Mac上的软件,其它我都开发过,想想,我他妈真是好学。
再仔细想来,我11年就开发过android软件,我应该是中国第一批开发android软件的人。
之所以列举上面这些,是因为这些东西,都对我后来做成这个软件有重要影响。
接着20年继续说,20年后半后没那么忙了,我在周末抽空又把那个 电脑工具软件 翻出来,把bug修复了一下,界面再优化了一下,并加入了 根据电脑设备id号(就是将 cpu、主板、硬盘的序列号组后然后用md5生成的64位编号)校验功能,并在软件上留下了我的微信号,于20年9月份,我将软件发布到小众软件这个网站上了,有好些人夸赞我这个软件很实用,还提到了软件存在的问题。然后我有空,就修复一下,接着发新版本。
然后,有人付款,5块的,10块的,20块钱的,我生成一个证书文件(里面就是一串字母,包含了软件什么时候到期等信息),记得第10月就收到400多元,有一次一个哥们,一开心,直接给我转了300元。真的感谢这个哥们,那时候我穷。
11月份卖了800多元,12月份1600元,好开心,够房租了。此时,我意识到,这个软件能挣大钱。我想把软件上传到360软件管家、腾讯电脑管家的时候,都要一个东西:软著。所以,我就开始写了软著材料,开始申请了。
一个软著从申请到下来,如果不出任何差错,最快也得一个半月。如果出错了,打回来,再提交,又得1个半月。再等给你把纸质的软著寄回来,那还得再等2个月。我前前后后弄了半年才把软著给整下来,软著拿到手已经是21年四五月份了。
21年,由于公司业务遇到瓶颈,公司内部各种矛盾,哎,伤心。
21年,记得是有一次去宝安沙井,我给我伙伴说(公司就3个人),咱把我这个软件好好推推吧,我感觉能挣到不少钱。不过,他们没放到眼里。
然后21年2月份就到2000元,2月份到了3000元,4月月份到了5000元了,5月份6000,到10月已经有1万多了。(这些数据不是真实数据,但量级是一样的,只是为说明每月都增加不少收入,我记得有一个月比前一个月翻倍了)
到了10月底,公司解散了,哎,操蛋。
在21年里,由于忙,我一直都是一边忙公司的事情,周末有空了就维护一下软件的问题,主要是各种闪退,菜单弹不出来,显示出错等,但是功能还是那么简单,UI还是那么的简陋。一边了就在知乎发发帖子,推广我的软件。
11月份,我就搬家了,换了一个稍微大点的房子,本想去找工作的,但想了想,快到年底了,加上 好多公司裁员,工作估计不好找,况且我这个软件有收入,我想投入时间好好再完善一下,然后再去上班。
在此后,我的重点放在以下方面:
以上4点缺一不可,不同阶段,重点不一样而已。
21年的11月、12月到22年的2月,这四项都在做,工作重要内容有:
这三个多月很寂寞,是在家一个人孤独寂寞地在做,我都瘦了好多,因为天天吃挂面和凉拌黄瓜。
22年春节过后,3月份,我和另外一个朋友合租了一个办公室。对,我也没去找工作,此时,我一个月能赚到1.5万了。
从21年的4月份,到22年3月份,我尝试着将价格提高,并分月、季、半年、年、终身等套餐,直到探索到一个 不能再高的价格为止,价格套餐此后再没变过。
到22年3月份,搬到合租的办公室上班。接着以下问题困扰着我:
所以,我就用我朋友的公司,花了半个月,弄了个微信、支付宝支付,再弄个了微信扫码登录功能,于五一前,终于上线了,我整个人都轻松了。
不过,要把钱提出来也是个问题,因为微信支付宝的钱,得先提到 业对公账户,对公账户的钱只能以工资或者其他手段弄出来,那么就得缴纳企业所得税、个税等。
到22年5月份,软件的功能基本上已经全了,bug很少很少了。此时,一个很重要的问题是,如何扩大规模,也就是推广。
我尝试过。
以上6点,只有第5条、第6条、第7条的效果是长远而且行之有效的。
到了22年6月之后,软件终于不用我怎么管了,自行运行,自动收钱,然后躺平了。用户每天在增加,收益变得起来起多。
截止今天,23年6月18号,我都做了八九款电脑端软件了(名字不能在这里说)。
22年初过年开始,花了3个月,做的一个软件,从2022-05-21 15:00:11第一笔收入,到今天,8977个用户,挣了7113元。没推广过,感觉没啥钱途。
22年10月份,做的一个软件,从2022-11-12 11:03:08第一笔收入到现在,348个用户,挣了1738元。这个软件感觉有钱途,打算好好推广一波。
其它好几款软件,也没推广过,软著还没下来,一直放着。估计感觉没没有钱途不好说,真的懒的推广。
乱七八遭的,总结一下吧:
我这个过程,我感觉都是不可复制的,各种尝试后的经验告诉我,如果你开发了一个软件:
一把年纪了,想去找工作,估计也找不到了。我打算 做外贸和其它软件,就这样一个人这样搞下去!
于2023年7月13日 21:40:00 内容补充
浪迹知乎多年,属实不敢相信这种题材的贴子能火,但它就象彩票中大奖的新闻中报道的一样,我第一次随手倍投了十几条经验,它就中了榜一。
1. 为啥文中不提软件名字?
能看这个帖子的,绝大多是程序员,肯定有人会攻击我的服务器,破解我的软件,网上盗版漫天飞。
2. 为啥匿名?
我的其它知乎帖子中,有我的软件介绍,会带来“问题1”的麻烦。
3. 辛苦吗?
这是文中的错觉。在21年10月份,公司解散的时候,我的软件每月就有不少收入了,生活过得去。公司解散后,反而没有那么压力大了,因为没有任务计划逼着我赶进度了。每天都是想把软件做大做强的动力,驱使着我兴致勃勃地干活,相比以前,起得更早了,睡得更晚了,精神头也更好了。在干活时,我也不是一直盯着ide全神心在干活,事实是我一边在刷剧,一边在干活。脑中贯注于代码,大脑易疲惫,电影电视剧是大脑的兴奋催化剂。一年能看大约500多小时的剧,好些剧反复看。
周星驰系列,金庸系列,成龙系列,李保田的《神医喜来乐》《宰相刘罗锅》,张译的《光荣时代》,祁厅长的《人民的名义》,李幼斌的《亮剑》,《大秦帝国》三步曲(第四步不感兴趣)《三国演义》《西游记》《铁齿铜牙纪晓岚》《大明风华》,动物世界相关,动画片《超能勇士》,韩剧《搞笑一家人》
有好剧的,推荐一下,最好是喜剧。
4. 关于吃挂面和凉拌黄瓜
这一段,本没想渲染生活很惨,可意外的是效果如此。原因在于,主食我只会煮挂面和泡面,炒菜只想炒大白菜、小白菜、包菜(清洗方便,切起来顺手,炒时熟的快),凉菜偏好黄瓜(叉板切片,撒盐,倒醋,三步搞定),讲究的是 简单、速度快、省事。
5. 为啥发这个贴子
没火之前,刷了那么多贴子,楞是没嫖到多少有用的经验,或者说分享的内容不太干,看了没多少收获。所以,我想抛砖引玉,如我当天的预测,这个贴子没啥人用。想不到20天后,也就前天(7月11号)晚上有人回贴了,我也用心回了,直到昨天中午我还在认真回贴中。昨天晚上,突然发现点赞、收藏、评论猛增,有点诧异。直到习惯性地刷新了一下热榜,才意识到这贴子上热榜了。
这下,我可真是慌了。本着无私分享,以心换心,换别人经验的态度,贴子和评论的回复中,有些敏感的不谐内容。评论中我就挖啊挖,删啊删。贴子不想删除,因为评论中也有一些有用的信息。读了好几遍贴子,改了好多次。晚上都没睡好。
6. 关于如何联系我
我只是一个很普通的程序员,联系我也没啥用,我只想匿名交流经验。我的网易“易信”app号 “ biexiabibi ”。
7. 是正经软件吗?
文中早早就说了,有软著,在360、腾讯软件管家上有上传,绝对是合法合规的软件。
8. 看知友,觉得很强?
这也是错觉。
我一直都感觉在小打小闹,见识如井底之蛙,好在有自知之明。因为这些经验都是我自己琢磨出来的,始终认为外面有高人,别人做得风生水起,我得多找别人交流。
关于编程,那纯粹是好学,和时间一年一年积累出来的,是螺丝钉的深度,是扳手的技能,造不了航母。
9. 关于UI?
能“致敬”就致敬,能拿来就拿来,当然我也会画UI草图,也会PS。
10. 关于技术框架和服务器负载流量等?
客户端就不说了,用你顺手的做出来就行。服务器很便宜,服务器端都是云,至于配置,你要是感觉客户端卡的时候,你自己分析问题在哪,然后升级配置。对于小众的软件来讲,基本就是验证用户登录会员等信息的,你买最底配置1核1G内存1M带宽就够了,一个月30元吧。
11. 如何判断这个软件是否有前途?
我可以提供一些判断这个软件是否有前途的小建议:
(1) 去各种搜索指数的地方看看相关关键词搜索量,微信搜索指数 抖音搜索指数 微博搜索指数 百度 360 搜狗搜索指数
(2) 去抖音 快手 小红书 微信搜索 百度360搜狗 知乎 微博 豆瓣 等去搜一下相关内容,各种关键词,反复试探搜索
(3) qq群,看看有没有相关群
(4) 看看同行的产品,加他们的qq群,打探敌情;去应用商店看评论,看看用户的评价。
(5) 发抖音,发朋友圈调研,看看大家的评论
(6) 发抖音,发朋友圈,假装你已经开发好了,需要的私信,看看大家的咨询购买意愿。花点钱,推一推。
(7) 一个软件要做成的环节很多,别人没做成功不代表你不可以做。有的人可能技术不行,有的人做出来的功能不全,或者没做到用户最重要的点上,有的人压根就没推广。我意思是,别人做过的,你也可以做。
(8) 有时候也可以蹭风口,比如现在流行的chatgpt,整一堆账号,搭建个代理,然后使劲在抖音打广告。赚一波就走。
(9) 做完以上,就到了你自己 做决定的时候了(至于怎么做,我也有点模糊),你凭感觉吧,哈哈。
至于怎么做决定,大的讲,就三点:你能做出来吗?你能营销卖出去吗?投入成本和获得的收益值得去做吗?
12. 做成免费软件然后用广告收费靠谱吗?
能收费就收费,否则就上广告,广告和收费你也可以一块上。至于怎么弄,这得综合考虑。因素有:竞争对手有没有,竞争对手的产品如何,竞争对手推广的好不好,目标用户的消费能力如何,目标用户对这个产品使用习惯,以及你的运营成本。
(1) 如果没竞争对手,或者别人都找不到竞争对手的产品,那就就收费,可劲提高收费,因为你相当于垄断。至于定价多少,小学六年级我们就学过餐厅菜定价问题。经观察,价格和顾客数量有一个线性关系,求定价多少,才能使利润最大化。
(2) 如果你有竞争对手,对手很牛,营销也很好,那么对手收费的,那你就比他便宜,或者免费。
总之,你一定要比别人有至少一个点的优势,如价格优势,或者 某个特有功能优势。
13. 脑袋空空的,没啥好创意,找不到感觉?
(1)去 小众应用 网站,360 腾讯软件管家,国外下载站,mac apple android 等应用网站多看看
(2)多用百度 微信 抖音 等搜索指数 看看一些关键词的搜索量
(3)多看广告,尤其抖音 百度 上的人家持续推广的软件相关的广告(重点)
(4)去看看一些任务外包平台,别人的小需求,可能蕴藏着大商机(重点)
(5)多看看别人在运营的软件,多琢磨它的盈利点,以及运营手段
(6)别人做过的,你也可以做,重点是 运营(重点)
多看多琢磨,积累素材,慢慢就有感觉了,能感觉哪些可以做,哪些不可以做。如果你不看不琢磨,脑袋空空,一点素材都没有,大脑如何联想、如何想象,如何迸发灵感,脑袋怎么可能有感觉了!≠
一个基于 Linux 操作系统的服务器运行的同时,也会表征出各种各样参数信息。通常来说运维人员、系统管理员会对这些数据会极为敏感,但是这些参数对于开发者来说也十分重要,尤其当你的程序非正常工作的时候,这些蛛丝马迹往往会帮助快速定位跟踪问题。这里只是一些简单的工具查看系统的相关参数,当然很多工具也是通过分析加工 /proc、/sys 下的数据来工作的,而那些更加细致、专业的性能监测和调优,可能还需要更加专业的工具(perf、systemtap 等)和技术才能完成哦。毕竟来说,系统性能监控本身就是个大学问。
➜ ~ top
第一行后面的三个值是系统在之前 1、5、15 的平均负载,也可以看出系统负载是上升、平稳、下降的趋势,当这个值超过 CPU 可执行单元的数目,则表示 CPU 的性能已经饱和成为瓶颈了。
第二行统计了系统的任务状态信息。running 很自然不必多说,包括正在 CPU 上运行的和将要被调度运行的;sleeping 通常是等待事件(比如 IO 操作)完成的任务,细分可以包括 interruptible 和 uninterruptible 的类型;stopped 是一些被暂停的任务,通常发送 SIGSTOP 或者对一个前台任务操作 Ctrl-Z 可以将其暂停;zombie 僵尸任务,虽然进程终止资源会被自动回收,但是含有退出任务的 task descriptor 需要父进程访问后才能释放,这种进程显示为 defunct 状态,无论是因为父进程提前退出还是未 wait 调用,出现这种进程都应该格外注意程序是否设计有误。
第三行 CPU 占用率根据类型有以下几种情况:
√ (us) user:CPU 在低 nice 值(高优先级)用户态所占用的时间(nice<=0)。正常情况下只要服务器不是很闲,那么大部分的 CPU 时间应该都在此执行这类程序
√ (sy) system:CPU 处于内核态所占用的时间,操作系统通过系统调用(system call)从用户态陷入内核态,以执行特定的服务;通常情况下该值会比较小,但是当服务器执行的 IO 比较密集的时候,该值会比较大
√ (ni) nice:CPU 在高 nice 值(低优先级)用户态以低优先级运行占用的时间(nice>0)。默认新启动的进程 nice=0,是不会计入这里的,除非手动通过 renice 或者 setpriority() 的方式修改程序的nice值
√ (id) idle:CPU 在空闲状态(执行 kernel idle handler )所占用的时间
√ (wa) iowait:等待 IO 完成做占用的时间
√ (hi) irq:系统处理硬件中断所消耗的时间
√ (si) softirq:系统处理软中断所消耗的时间,记住软中断分为 softirqs、tasklets (其实是前者的特例)、work queues,不知道这里是统计的是哪些的时间,毕竟 work queues 的执行已经不是中断上下文了
√ (st) steal:在虚拟机情况下才有意义,因为虚拟机下 CPU 也是共享物理 CPU 的,所以这段时间表明虚拟机等待 hypervisor 调度 CPU 的时间,也意味着这段时间 hypervisor 将 CPU 调度给别的 CPU 执行,这个时段的 CPU 资源被“stolen”了。这个值在我 KVM 的 VPS 机器上是不为 0 的,但也只有 0.1 这个数量级,是不是可以用来判断 VPS 超售的情况?
CPU 占用率高很多情况下意味着一些东西,这也给服务器 CPU 使用率过高情况下指明了相应地排查思路:
√ 当 user 占用率过高的时候,通常是某些个别的进程占用了大量的 CPU,这时候很容易通过 top 找到该程序;此时如果怀疑程序异常,可以通过 perf 等思路找出热点调用函数来进一步排查;
√ 当 system 占用率过高的时候,如果 IO 操作(包括终端 IO)比较多,可能会造成这部分的 CPU 占用率高,比如在 file server、database server 等类型的服务器上,否则(比如>20%)很可能有些部分的内核、驱动模块有问题;
√ 当 nice 占用率过高的时候,通常是有意行为,当进程的发起者知道某些进程占用较高的 CPU,会设置其 nice 值确保不会淹没其他进程对 CPU 的使用请求;
√ 当 iowait 占用率过高的时候,通常意味着某些程序的 IO 操作效率很低,或者 IO 对应设备的性能很低以至于读写操作需要很长的时间来完成;
√ 当 irq/softirq 占用率过高的时候,很可能某些外设出现问题,导致产生大量的irq请求,这时候通过检查 /proc/interrupts 文件来深究问题所在;
√ 当 steal 占用率过高的时候,黑心厂商虚拟机超售了吧!
第四行和第五行是物理内存和虚拟内存(交换分区)的信息:
total = free + used + buff/cache,现在buffers和cached Mem信息总和到一起了,但是buffers和cached Mem 的关系很多地方都没说清楚。其实通过对比数据,这两个值就是 /proc/meminfo 中的 Buffers 和 Cached 字段:Buffers 是针对 raw disk 的块缓存,主要是以 raw block 的方式缓存文件系统的元数据(比如超级块信息等),这个值一般比较小(20M左右);而 Cached 是针对于某些具体的文件进行读缓存,以增加文件的访问效率而使用的,可以说是用于文件系统中文件缓存使用。
而 avail Mem 是一个新的参数值,用于指示在不进行交换的情况下,可以给新开启的程序多少内存空间,大致和 free + buff/cached 相当,而这也印证了上面的说法,free + buffers + cached Mem才是真正可用的物理内存。并且,使用交换分区不见得是坏事情,所以交换分区使用率不是什么严重的参数,但是频繁的 swap in/out 就不是好事情了,这种情况需要注意,通常表示物理内存紧缺的情况。
最后是每个程序的资源占用列表,其中 CPU 的使用率是所有 CPU core 占用率的总和。通常执行 top 的时候,本身该程序会大量的读取 /proc 操作,所以基本该 top 程序本身也会是名列前茅的。
top 虽然非常强大,但是通常用于控制台实时监测系统信息,不适合长时间(几天、几个月)监测系统的负载信息,同时对于短命的进程也会遗漏无法给出统计信息。
vmstat 是除 top 之外另一个常用的系统检测工具,下面截图是我用-j4编译boost的系统负载。
r 表示可运行进程数目,数据大致相符;而b表示的是 uninterruptible 睡眠的进程数目;swpd 表示使用到的虚拟内存数量,跟 top-Swap-used 的数值是一个含义,而如手册所说,通常情况下 buffers 数目要比 cached Mem 小的多,buffers 一般20M这么个数量级;io 域的 bi、bo 表明每秒钟向磁盘接收和发送的块数目(blocks/s);system 域的 in 表明每秒钟的系统中断数(包括时钟中断),cs表明因为进程切换导致上下文切换的数目。
说到这里,想到以前很多人纠结编译 linux kernel 的时候 -j 参数究竟是 CPU Core 还是 CPU Core+1?通过上面修改 -j 参数值编译 boost 和 linux kernel 的同时开启 vmstat 监控,发现两种情况下 context switch 基本没有变化,且也只有显著增加 -j 值后 context switch 才会有显著的增加,看来不必过于纠结这个参数了,虽然具体编译时间长度我还没有测试。资料说如果不是在系统启动或者 benchmark 的状态,参数 context switch>100000 程序肯定有问题。
如果想对某个进程进行全面具体的追踪,没有什么比 pidstat 更合适的了——栈空间、缺页情况、主被动切换等信息尽收眼底。这个命令最有用的参数是-t,可以将进程中各个线程的详细信息罗列出来。
-r:显示缺页错误和内存使用状况,缺页错误是程序需要访问映射在虚拟内存空间中但是还尚未被加载到物理内存中的一个分页,缺页错误两个主要类型是
√ minflt/s 指的 minor faults,当需要访问的物理页面因为某些原因(比如共享页面、缓存机制等)已经存在于物理内存中了,只是在当前进程的页表中没有引用,MMU 只需要设置对应的 entry 就可以了,这个代价是相当小的
√ majflt/s 指的 major faults,MMU 需要在当前可用物理内存中申请一块空闲的物理页面(如果没有可用的空闲页面,则需要将别的物理页面切换到交换空间去以释放得到空闲物理页面),然后从外部加载数据到该物理页面中,并设置好对应的 entry,这个代价是相当高的,和前者有几个数据级的差异
-s:栈使用状况,包括 StkSize 为线程保留的栈空间,以及 StkRef 实际使用的栈空间。使用ulimit -s发现CentOS 6.x上面默认栈空间是10240K,而 CentOS 7.x、Ubuntu系列默认栈空间大小为8196K
-u:CPU使用率情况,参数同前面类似
-w:线程上下文切换的数目,还细分为cswch/s因为等待资源等因素导致的主动切换,以及nvcswch/s线程CPU时间导致的被动切换的统计
如果每次都先ps得到程序的pid后再操作pidstat会显得很麻烦,所以这个杀手锏的-C可以指定某个字符串,然后Command中如果包含这个字符串,那么该程序的信息就会被打印统计出来,-l可以显示完整的程序名和参数
➜ ~ pidstat -w -t -C “ailaw” -l
这么看来,如果查看单个尤其是多线程的任务时候,pidstat比常用的ps更好使!
当需要单独监测单个 CPU 情况的时候,除了 htop 还可以使用 mpstat,查看在 SMP 处理器上各个 Core 的工作量是否负载均衡,是否有某些热点线程占用 Core。
➜ ~ mpstat -P ALL 1
如果想直接监测某个进程占用的资源,既可以使用top -u taozj的方式过滤掉其他用户无关进程,也可以采用下面的方式进行选择,ps命令可以自定义需要打印的条目信息:
while :; do ps -eo user,pid,ni,pri,pcpu,psr,comm | grep ‘ailawd’; sleep 1; done
如想理清继承关系,下面一个常用的参数可以用于显示进程树结构,显示效果比pstree详细美观的多
➜ ~ ps axjf
iotop 可以直观的显示各个进程、线程的磁盘读取实时速率;lsof 不仅可以显示普通文件的打开信息(使用者),还可以操作 /dev/sda1 这类设备文件的打开信息,那么比如当分区无法 umount 的时候,就可以通过 lsof 找出磁盘该分区的使用状态了,而且添加 +fg 参数还可以额外显示文件打开 flag 标记。
2.1 iostat
➜ ~ iostat -xz 1
其实无论使用 iostat -xz 1 还是使用 sar -d 1,对于磁盘重要的参数是:
√ avgqu-s:发送给设备 I/O 请求的等待队列平均长度,对于单个磁盘如果值>1表明设备饱和,对于多个磁盘阵列的逻辑磁盘情况除外
√ await(r_await、w_await):平均每次设备 I/O 请求操作的等待时间(ms),包含请求排列在队列中和被服务的时间之和;
√ svctm:发送给设备 I/O 请求的平均服务时间(ms),如果 svctm 与 await 很接近,表示几乎没有 I/O 等待,磁盘性能很好,否则磁盘队列等待时间较长,磁盘响应较差;
√ %util:设备的使用率,表明每秒中用于 I/O 工作时间的占比,单个磁盘当 %util>60% 的时候性能就会下降(体现在 await 也会增加),当接近100%时候就设备饱和了,但对于有多个磁盘阵列的逻辑磁盘情况除外;
还有,虽然监测到的磁盘性能比较差,但是不一定会对应用程序的响应造成影响,内核通常使用 I/O asynchronously 技术,使用读写缓存技术来改善性能,不过这又跟上面的物理内存的限制相制约了。
上面的这些参数,对网络文件系统也是受用的。
网络性能对于服务器的重要性不言而喻,工具 iptraf 可以直观的现实网卡的收发速度信息,比较的简洁方便通过 sar -n DEV 1 也可以得到类似的吞吐量信息,而网卡都标配了最大速率信息,比如百兆网卡千兆网卡,很容易查看设备的利用率。
通常,网卡的传输速率并不是网络开发中最为关切的,而是针对特定的 UDP、TCP 连接的丢包率、重传率,以及网络延时等信息。
➜ ~ netstat -s
显示自从系统启动以来,各个协议的总体数据信息。虽然参数信息比较丰富有用,但是累计值,除非两次运行做差才能得出当前系统的网络状态信息,亦或者使用 watch 眼睛直观其数值变化趋势。所以netstat通常用来检测端口和连接信息的:
netstat –all(a) –numeric(n) –tcp(t) –udp(u) –timers(o) –listening(l) –program(p)
–timers可以取消域名反向查询,加快显示速度;比较常用的有
➜ ~ netstat -antp #列出所有TCP的连接
➜ ~ netstat -nltp #列出本地所有TCP侦听套接字,不要加-a参数
sar 这个工具太强大了,什么 CPU、磁盘、页面交换啥都管,这里使用 -n 主要用来分析网络活动,虽然网络中它还给细分了 NFS、IP、ICMP、SOCK 等各种层次各种协议的数据信息,我们只关心 TCP 和 UDP。下面的命令除了显示常规情况下段、数据报的收发情况,还包括
TCP
➜ ~ sudo sar -n TCP,ETCP 1
√ active/s:本地发起的 TCP 连接,比如通过 connect(),TCP 的状态从CLOSED -> SYN-SENT
√ passive/s:由远程发起的 TCP 连接,比如通过 accept(),TCP 的状态从LISTEN -> SYN-RCVD
√ retrans/s(tcpRetransSegs):每秒钟 TCP 重传数目,通常在网络质量差,或者服务器过载后丢包的情况下,根据 TCP 的确认重传机制会发生重传操作
√ isegerr/s(tcpInErrs):每秒钟接收到出错的数据包(比如 checksum 失败)
UDP
➜ ~ sudo sar -n UDP 1
√ noport/s(udpNoPorts):每秒钟接收到的但是却没有应用程序在指定目的端口的数据报个数
√ idgmerr/s(udpInErrors):除了上面原因之外的本机接收到但却无法派发的数据报个数
当然,这些数据一定程度上可以说明网络可靠性,但也只有同具体的业务需求场景结合起来才具有意义。
tcpdump 不得不说是个好东西。大家都知道本地调试的时候喜欢使用 wireshark,但是线上服务端出现问题怎么弄呢?
附录的参考文献给出了思路:复原环境,使用 tcpdump 进行抓包,当问题复现(比如日志显示或者某个状态显现)的时候,就可以结束抓包了,而且 tcpdump 本身带有 -C/-W 参数,可以限制抓取包存储文件的大小,当达到这个这个限制的时候保存的包数据自动 rotate,所以抓包数量总体还是可控的。此后将数据包拿下线来,用 wireshark 想怎么看就怎么看,岂不乐哉!tcpdump 虽然没有 GUI 界面,但是抓包的功能丝毫不弱,可以指定网卡、主机、端口、协议等各项过滤参数,抓下来的包完整又带有时间戳,所以线上程序的数据包分析也可以这么简单。
下面就是一个小的测试,可见 Chrome 启动时候自动向 Webserver 发起建立了三条连接,由于这里限制了 dst port 参数,所以服务端的应答包被过滤掉了,拿下来用 wireshark 打开,SYNC、ACK 建立连接的过程还是很明显的!在使用 tcpdump 的时候,需要尽可能的配置抓取的过滤条件,一方面便于接下来的分析,二则 tcpdump 开启后对网卡和系统的性能会有影响,进而会影响到在线业务的性能。
欢迎大家一起学习交流
下文提供 ZFile 镜像构建过程,供大家参考。
1 | FROM ibm-semeru-runtimes:open-8-jre |
FROM ibm-semeru-runtimes:open-8-jre
表示使用的基础镜像,这里选中的这个是 ibm
的 openj9
jdk8
版本的 jre
,这个版本的 jdk 具有内存占用小,启动速度快等优势,且针对 docker
环境做过特殊优化。WORKDIR /root
表示工作目录在 /root
,下方所有命令将在这个目录下执行RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
和 RUN echo 'Asia/Shanghai' >/etc/timezone
表示设置时区为上海时间,这两个设置的区别参考:https://unix.stackexchange.com/questions/384971/whats-the-difference-between-localtime-and-timezone-filesRUN curl -o app.jar https://c.jun6.net/ZFILE/zfile-release.jar
表示下载 zfile
最新版 jar
包,并命名为 app.jar
,因为上方工作目录为 /root
,所以实际下载到了 /root/app.jar
EXPOSE 8080
表示容器可能会使用这个端口,这个只是声明或备注式的,不会实际影响端口情况。ENTRYPOINT java $JAVA_OPTS -Xshareclasses -Xquickstart -jar /root/app.jar
表示启动 /root/app.jar
,其中 -Xshareclasses -Xquickstart
是 ibm
的 openj9 jvm
的参数,用来优化内存占用。由于需要同时支持 arm64
架构和 amd64
架构,所以使用的 docker
的 多平台构建,即同时 build
多个架构的镜像。
Docker
默认的 builder
实例不支持同时指定多个 --platform
,我们必须首先创建一个新的 builder
实例。1 | docker buildx create --name zfile-builder --driver docker-container |
builder
实例1 | docker buildx use zfile-builder |
builder
支持构建的架构类型1 | docker buildx ls |
1 | docker run --privileged --rm tonistiigi/binfmt --install all |
Dockerfile
所在目录执行构建命令并 push
到 docker hub
(需提前 docker login
账号)1 | docker buildx build --platform linux/arm64,linux/amd64 -t zhaojun1998/zfile:latest --push . |
然后在 docker hub
就可以看到推送的镜像了。
[
后续还会更新如何使用 CI
工具自动化构建镜像的方式。
mac catalina 通过homebrew 安装 openssl 失败,被嫌弃系统太老,make test 测试不通过
I manually installed openssl@3 with the following commands
https://www.openssl.org/source/openssl-3.1.1.tar.gz
perl ./Configure --prefix=/usr/local --openssldir=/usr/local/openssl no-ssl3 no-ssl3-method no-zlib darwin64-x86_64-cc enable-ec_nistp_64_gcc_128
make
make test
(optional) I passed all testssudo make install MANDIR=/usr/local/Cellar/openssl@3/3.1.1_1/share/man MANSUFFIX=ssl
openssl version
(optional - verification). It should report OpenSSL 3.1.1 30 May 2023 (Library: OpenSSL 3.1.1 30 May 2023)which -a openssl
(optional).brew link openssl@3
brew list
(optional) you should see the openssl@3 inside installed packages.我有一台用了十年的 mac mini,这台电脑的质量还是不错的。虽然也升级了内存和硬盘。 这个没怎么清过灰的家伙也一直没坏。稳定地发挥一个 HTPC 的作用。 不过苹果是已经放弃了它,最终它停留在 catalina。 不过最近我遇到了点麻烦:onedrive 打不开了。
本文使用到了 homebrew,如果你没有或不能使用 brew,请参考另一篇:
目前看来,这是微软推送了一个未在 catalina 上验证过的更新,目前问题已修复, 可以直接安装到最新版,如果您已经使用了本文的方法关闭了自动更新, 那么删掉现有 OneDrive 程序重新安装即可。下次微软再犯相同错误,可以如法炮制。
某天,OneDrive 突然提示我它已经损坏了,重启也没什么反应。 我的第一反应是 mini 用的这块 ssd 大限到了, 不过后来看看其他程序和文件似乎也都正常,感觉又不太像是 ssd 的寿命问题。
如果不是 ssd 的寿命问题,之前 OneDrive 也是好好的,那么估计就是更新出问题了, 我的 OneDrive 是在 app store 安装的,打开商店看了一下,最近 OneDrive 果然有更新。
第一回合我们自然是先重装试试看能不能修复,顺带一提, OneDrive 内部有一个重置的命令,可以把 OneDrive 重置到出厂状态, 右键点击 OneDrive 应用,点击「显示包内容」:
接下来就可以在 Contents/Resources 下找到 ResetOneDriveApp.command:
双击运行就好,不过写在这里你应该可以猜到,这个和重装都没能解决问题。
首先我们要安装旧版本的应用,很显然 app store 是没办法更新到指定版本的, 不过 brew 可以,只是需要一些小手段。
首先我们在 Homebrew Formulae 中找到 onedrive 的页面, 从这个页面我们可以找到 OneDrive 的 Cask code, 点击 history:
这时我们就可以看到近期的更新,我打算更新到 2 月 23 日的版本, 我们点击 #141750 右边「查看当时的代码」
接下来 raw 按钮给出的就是 当时的 cask code 了,我们可以下载下来,使用以下命令安装:
1 | brew install --cask onedrive.rb |
安装好以后,千万不要立即执行 OneDrive!因为 OneDrive 自身也内嵌了更新机制, 一旦启动了 OneDrive,它就会自作聪明地自作主张, 把我们好不容易装上去的旧版更新为无法启动的最新版。
一个 OneDrive,三个更新进程,我们索性把它们全关掉:
1 | launchctl remove com.microsoft.OneDriveStandaloneUpdater |
一不做二不休,配置文件也删了好了:
1 | sudo rm /Library/LaunchAgents/com.microsoft.OneDriveStandaloneUpdater.plist |
这时我们再启动 OneDrive,整个世界清净了。
如果你还在使用 catalina,并且也在使用 OneDrive 时,那么大概率会遇到这个问题, 其实我理解微软的做法,淘汰某个古老系统是正常的,更新也是按正常逻辑运行的, 但是两个加在一起,老系统就不正常了,这不能作为让用户承担问题的理由, 起码应该下发一个版本,停止旧版本的自动更新,再接下来向新系统下发更新。 不过我的牢骚微软应该是听不到的,如果你也有这个问题,那么请按以下步骤尝试:
今天把Ubuntu系统的ShadowsocksR/SSR的一键脚本也补齐了,目前已经上传到 Github。CentOS系统请参考: ShadowsocksR/SSR一键脚本
提示:这是自行搭建科学上网环境的第三步,请确认已经做了前两步:
注意:
登录到购买好的Linux服务器(windows可参考 Bitvise连接Linux服务器教程,mac用户请参考 Mac电脑连接Linux教程),在终端(黑框框)里输入如下命令:
1 | bash <(curl -sL https://raw.githubusercontent.com/hijkpw/scripts/master/ubuntu_install_ssr.sh) |
按回车键,屏幕出现“请设置SSR的密码(不输入则随机生成)” 的提示,按照提示设置密码(SSR的密码。例如1234abcd,不是服务器网页后台的密码)、端口(SSR的端口,例如12345,不能是22和80)并选择加密方式。
接下来屏幕上开始疯狂出现一堆你看得懂看不懂的东西,如果安装过程中卡住,请耐心等待几分钟;安装期间网络断开(windows上表现为黑框框中或者顶部标题出现disconnected字样,mac表现为终端出现“closed by remote host”或”broken pipe”),请重新连接后再次执行命令。安装成功的界面如下:
[
ubuntu ssr成功提示信息
到此服务端配置完毕,服务器可能会自动重启(没提示重启则不需要),windows终端出现“disconnected”,mac出现“closed by remote host”说明服务器重启了。
SSR一键脚本做了如下事情:
接下来是科学上网最后一步:下载客户端,并参考页面中的配置教程进行配置:
ShadowsocksR/SSR windows客户端下载
ShadowsocksR/SSR安卓客户端下载
ShadowsocksR/SSR mac客户端下载
ShadowsocksR/SSR ios客户端下载
下载客户端配置好后,就可以愉快的上外网了!
bash <(curl -sL https://raw.githubusercontent.com/hijkpw/scripts/master/ubuntu_install_ssr.sh) info
systemctl start shadowsocksR
;停止:systemctl stop shadowsocksR
;重启:systemctl restart shadowsocksR
;bash <(curl -sL https://raw.githubusercontent.com/hijkpw/scripts/master/ubuntu_install_ssr.sh) uninstall
。