你这么一 or 怎么判断这里面该打印 fizz buzz 还是 fizzbuzz?
偷换概念了。让你掌握基础没让你成为数学家。所有的 101 课程都是从 Hello World 开始的,算法是基础了,Hello World 就不是了?
我还能写出一个不含分号一行解决的解。
puts 'The answer is ' + (1..100).to_a.bsearch { |x| (input = [(print ">> Is it #{x}? [too high/too low/yes(default)]: "), gets.chomp][1]) == 'too low' ? 1 : input == 'too high' ? -1 : 0 }.to_s
给个短小的解
puts 'The answer is ' + (1..100).to_a.bsearch { |x|
print ">> Is it #{x}? [too high/too low/yes(default)]: "
(input = gets.chomp) == 'too low' ? 1 : input == 'too high' ? -1 : 0
}.to_s
这些还真是锻炼基本逻辑的题,推荐白板练习
我觉得你见过培训班学生在 2017 年写出 2010 年风格的代码的时候就知道为什么这些学生没有救。这个行业一直在高速发展,而他们的发展越来越局限,因为他们只能越来越熟练处理自己熟悉的东西,却没有接受新事物的能力。更惨痛的是,这些人是现在接受培训的主体。
这个假设就好像如果我们飞到月球不要钱一样,是不切实际的。 为什么培训班没有这么操作或者大学很少这么操作的的就是因为这么操作产量太不稳定。首先能设计出能说清 SICP 课程的老师难度就非常高,对学生的要求更不是零门槛的了。中国大学在持续的扩招之下,太多无法接收如此专业教育的人都进入了大学,这使得不可能设计出真正专业的课程。一些学校,甚至是一些 985 大学,会选择通过默写来考察算法课,因为如果真的考算法,那一半人就别毕业了。 如果说一个培训班能设计出这种课程,而且还能压缩到一个合理的培训班课时的话,而不是业余五年六年的话,那么这个培训班接收的学生只可能本身就极具天赋,且恰好没有收到专业教育的这种情况。这样的班有可能开出来吗?培训班是要赚钱的,除非这是个公益组织还差不多。
如果以我国来讲的话,除了少数几个学校,专业教育的大部分也不靠谱。为什么指导不能来自培训机构呢?因为四年安排的课程和几个月的能一样吗?你见过哪个培训班讲 SICP 吗?有哪个培训班老师会让你课余去看看 TAOCP 的习题吗?年轻人是要好的指导,但你连在线找到合适的学习材料都做不到这怎么能行呢?难道打算半年经验用九年半吗?
然而问题是我们之所以要考算法是为了考察你写代码的逻辑能力。如果你通过刷 LeetCode 之类的方法来学会常见的算法题,本质上并不会掌握这些东西,某种意义上这不就是来骗面试的行为嘛。我如果把一个常见的题目外面套一层壳,不又会暴露嘛。
现在某些学校算法课考默写,编译原理没大作业,这些课早年都是用来「教」的,现在呢?大学扩招这么多年,大学生越来越多,大学生的整体素质呢?大学「该」教会学生什么,现在弄得「什么都教不会」好像是一件正常的事情一样。
前段时间去日本的时候还特意了解了当地的软件行业。由于日本「正社员」的制度,他们筛选人才主要看人品和学习能力,对技术本身却不看重。进去再给个半年培训,再通过工作慢慢补回来,一种说不出来的感觉。
我在发帖后的 1 小时内收到了不少于 5 封私信有关于吐槽某个全栈营毕业的学员的面试情况了。。。
对,我不认为 CodeSchool 或者 Codecademy 之类的有问题,因为他摆明了是教你工具去的,也没有给你什么过高的期望。就好像同样的内容你叫《C++ 入门》,我不认为你有问题,你叫《21 天精通 C++》,那你就是骗子。
原始的 issue 下通过开放地址法写了几个 candidate,针对这几个 candidate 的 benchmark 实在是非常玄妙。
我最近打算写一下,感觉直接对接 CDN 的话不是太麻烦
#25 楼 @gihnius 很多稳定性问题主要是 eventmachine 本身导致的,而不是异步。我也打算在下一个大版本中把基于 eventmachine 的绑定改成基于 nio4r 的绑定。rust 线程比 gorouting 快很多,但是 rust 上基于的 tokio-rust 的网络通讯会比线程更快。扯到 IO 的时候,只有在完全解决阻塞的情况下,问题才会落在内存、网络、磁盘上,一旦出现线程阻塞,那性能必定是非常糟糕的。异步的做法就是用来解决阻塞问题的,但是异步的做法代码很难看,这才是这几年很多语言设计都在极力克服的问题。高性能的 Web 服务器,从 Apache 到 nginx 没有一个不是在使用 I/O 多路复用技术来解决问题,甚至连使用哪种复用技术都经过了几代的改变,更不要说单纯同步靠创建线程来解决 I/O 导致的线程阻塞,运行效率实在是太低下。
IO 密集型还是用线程。
这种表述实在是难以苟同,你基本找不到单机 10k 并发以上的应用是通过纯线程来解决的,因为单纯靠创建新线程,*NIX 线程创建的性能代价是极大的。
#23 楼 @mizuhashi 在多线程下不会阻塞是指,他们在多个线程连接数据库的时候互不阻塞,但对于当前线程就出于阻塞状态了,我在实现 pg 的 adapter 的时候就发现了这一问题。主要是大家没有共享同一个 event loop
有点奇怪,既然是 Let's encrypt 的证书,为什么不直接申请呢?在又拍云上申请 Let's encrypt 证书有什么区别?
怎么看都像是脱裤啊。。。
这帖子让我想起来不少事情。我自己从 BASIC 开始 Delphi, C++, PHP, Python, Java, JavaScript, Scala, Objective-C, Ruby, Common Lisp, Swift 都先后学过。最后想想语言和框架真的是这么好学的东西吗?是也不是。
是的部分是语言的语法确实是一通百通的,基本就可以分为类 C 语言和类 Lisp 语言这两大类。不是的部分是,如果大家的设计都这么接近,那么为什么会有这么多语言呢?事实上,理解一门语言的重要部分就是理解这门语言的设计思想。
如果你会写 C++,学习 Java 的第一天你就可以开始干活了,但你很容易写出 C++ 风格的 Java。这就好像谭浩强的 C 语言书有那么多问题,除了本身的语法问题,一个就是对于语言设计思想本身谭浩强不理解,另一个就是保有了大量谭浩强之前 BASIC 程序员的风格。
所以如果你学过很多语言,学得好,你优势就会很大。比如你又会写后端,又掌握前端,在你开发时你就能很好的对接,设计出更合适的接口,极大地提高沟通和开发的效率。学得不好,那么这些东西反而会成为阻碍,让你什么事情都没法做好。这是全栈工程师和全栈 Hello World 工程师最大的区别。
不过反过来说,如果只学一样东西,即使这项技术没有过时,那么你就能专精了吗?其实也不是。很多外包公司的 Java 程序员所谓的 10 年经验难道不是半年经验用九年半吗?
所以本质上来说,要想有好的职业规划,需要对自己有明确的认识。永远知道自己知识薄弱的地方,永远知道自己要学习要接触新的东西。好的程序员其实吃饭的时候在想怎么更好抽象,排队的时候在想怎么提高性能,洗澡的时候在想怎么优化风格。用框架用语言的同时会提出这些框架语言设计的问题,并思考能不能解决,怎么解决,这样才能对这些东西理解更加深刻,这样才能让自己写起代码来游刃有余。
其实真的好好思考后,就算是业务代码也并不会繁杂。业务逻辑上的繁杂通常就是由于没有正确的抽象,从一开始就没有好好做好,从而使得复杂度越来越高,永远是打补丁,在补丁上打补丁,代码越来越糟糕,最后让思路越发混乱,越发不能维护。如果是这种情况,别说 Rails,世界上任何一种语言、一个框架都能写出这种垃圾代码出来。
于是说,如果因为自己买了台 iPhone,就能荒废 Android 开发的技能,这种坚持和努力程度实在是太低了。我很难苟同说楼主现在这样的情况的主要原因是环境造成的。
#18 楼 @harryyoung 我觉得我要把 em- 彻底拿掉。。。
这样的问题就不是说依靠异步模型本身去解决的,因为这些场景出现的是真正的 CPU 密集运算 需要的是真正的计算力来解决的。如果说我们只有一个核心一个线程可用的情况下,任何 Web 框架,包括 Node 也好,都会出现同样的性能下滑。只有说我们靠多线程多进程来解决,类似于 express 的 clusters;类似于 Ruby 上的 puma。
另外你给的 benchmark 代码,如果限制 thin 只能在一个核心上运行的话,em-midori 并不会比 thin 慢一倍。(在 Linux 上的性能测试,macOS 上的 em-midori 有一些奇怪的性能问题,还在排查。)这和 em-midori 目前还没有实现 clusters 功能有关,这是下一个版本的工作重点之一。
另外我不能理解所说的
难以保证 Promise 的方式是可靠的,且性能不低于常规方式
因为这个 Promise 是按照 Node 新版本的思路一致实现的,如果说可能存在一些边缘情况,这些之后会通过更完整的单元测试来补充。而使用 Fiber 的封装肯定会比 UNIX 线程方式的性能高,这点应该是毋庸置疑的。
#10 楼 @0x005a 不,receive_data
一上来就对 Fiber 干了一些特殊的处理。也就是认为 receive_data
里的任何东西都一个 async
函数,
# Logic of receiving data
# @param [String] data raw data
def receive_data(data)
lambda do
async_internal(Fiber.new do
#...
receive_new_request(data)
#...
)
end.call
end
而 async_internal
的实现是
def async_internal(fiber)
chain = lambda do |result|
return unless result.is_a?Promise
result.then(lambda do |val|
chain.call(fiber.resume(val))
end)
end
chain.call(fiber.resume)
end
所以 Fiber.yield
只会阻塞当前请求,同时将处理权让渡给下一个 EventMachine
循环,并不会阻塞主线程。
之所以你上面给出的
require 'em-midori'
class Route < Midori::API
get '/' do
sleep 1; ''
end
end
Midori::Runner.new(Route).start
将并发降到了 1,是因为 Kernel.sleep 函数本身没有被封装。
em-midori 与其说是一个异步的 Web 框架,不如说是提供了一系列无回调非阻塞 I/O 的工具集合。
事实上,你可以利用 EM.add_ticker
放在 em-midori
定义的 Promise 类里套一下,就可以得到一个不会影响并发的计时器。defer
是个方法,但用来做计时器还是有些重。
em-midori
内置了 Postgres 和 Sequel 的封装,使用样例如下:
Postgres:
require 'em-midori'
require 'em-midori/extension/postgres'
Midori::Configure.before = proc do
DB = Midori::Postgres.new('127.0.0.1', 5432)
DB.connect('dbname', 'username', 'pwd')
end
class Route < Midori::Route
get '/' do
DB.query('SELECT * FROM TEST WHERE A=0')
''
end
end
Sequel:
require 'em-midori'
require 'em-midori/extension/sequel'
Midori::Configure.before = proc do
DB = Sequel.connect('postgres://username:pwd@localhost:5432/dbname')
class User < Sequel::Model
end
end
class Route < Midori::Route
get '/' do
User.find(a: 0)
''
end
end
em-synchrony
其实本身写得也很好,我在写这个框架之前仔细读完了 em-synchrony
的代码,但 em-synchrony
的主要目的是利用 Fiber 实现更灵活的异步调用语法。但 em-midori
更大的意义是通过封装,尽可能减少在业务层加入异步相关的语法。虽然实现途径非常类似,但是目标还是有很大区别的。