线程和锁
- 线程锁的的问题:
时序问题
原子操作问题(Java内存读写机制->读.改.写)
竞态条件(操作取决于线程执行的先后顺序)
JVM优化导致的问题(编译器静态优化,JVM动态优化,硬件指令的乱序执行)
两把锁:死锁问题
外部方法或者对象的线程安全问题
效率问题synchronized()
ThreadLocal额外讲解,线程级别的局部变量,适用于数据库连接,网络请求
- 使用concurrency
ReetrantLock的手动加锁解锁
死锁也能中断(不推荐的方式lockInterruptibly())
tryLock()虽然能设定超时自动解锁,但是缺点明显:活锁(同时死锁再同时超时)
条件锁:Condition类
原子操作:Atomic 简单的解决方法,坑和缺点
线程池 内置的Exeutors.newFixedThreadPool()
函数式方法
- 变量与可变状态导致的并发难题的终极解决方法->去掉变量
函数式基础概念:顺序无关 map reduce 无穷序列和惰性求值 尾递归
Clojure简单方法:pmap
两种Clojure并发模型:Future(给定一个函数在新线程跑,返回一个future对象) Promise(立即返回,惰性,调用deliver才会执行)
原子变量(atom),代理(deref @),由引用(ref)构成的软件事务内存(STM)。对任何多个并发事务进行修改发生冲突,将会导致重试
actor的魔力(略)
- 纯粹的消息式的交流,几乎没有限制的进程数,随时加入和进行任务,任由错误发生,集中处理
actor:真正的消息传递,轻量级的进程开销
分布式map,每个进程分配子map
个人笔记-《高级数据结构》
内容
- Why and how O(log n) access time?
- Dynamic data structure and Analysis
- Randomized Data Structure
- Augmented Data Structure
- Data Structures in Distributed Environments
- Data Structures in Frontiers of Research
- Exam
逆序对
- 随即序列 逆序对为 n(n-1)/4
- 证明:全逆序序列 ,如 5,4,3,2,1,则总计4+3+2+1,共Cn(2)个,即n(n-1)/2
- 交换相邻元素的本质:消除一对逆序
第一次Hackathon之旅
启程
上周之前,我参加了由GitCafe举办的《开源者行》的上海站,在那里,不仅见识到了很多非常出色的小伙伴,最终的Ideathon上面,我们小组获得了优胜并且我被邀请组队参加了这次的Hackathon。
我们这组小队都是《开源者行》选出的来的,有自北航的林泉沛
(ACM算法向)、来自上交的卢涛南
(JavaScript好手)、还有来自福建的温荣泉
(Unity开发者),在经过1周的水群和漫无止境的脑洞之后,还是没有最终定下Idea。不过Whatever,大家还是非常乐观的一同奔赴武汉。
6月5号,经过长达5小时的旅途(又是一段坑人的旅途),我终于成功面基,林大大展现出他的学长风范,带我小转并且吃了一顿,并深深的体会到了繁华的武汉的意义(对比南京郊区,我感到了深深的恶意……)我、林大还有温荣泉住在一起,大家又快速脑洞了一下,基本提出了几个点子,为了养精蓄锐,大家也就不浪了,快快入睡。
开始
开源者行-见识更大的世界
简单的FP中思想在实际小项目中的应用
函数式编程,无论是谁,第一次听到都会感到好奇,疑惑以及畏惧。因为一提到函数式编程就会让人想到很多数学或者计算机科学理论研究的深奥原理,无论是Lamda演算还是高阶函数,似乎都和平常自己所接触到的编程语言毫无关系。
随着现代语言的发展,大多数传统面向对象语言已经支持了很多函数式编程中的语法,比如说:
闭包:就是指一个函数块,把连同这个函数所需要的所有参数(全局的or局部的)放入一个闭包中,然后这个函数可以单独用来执行,不会因为外部变量被修改而产生额外影响。相当于这个函数的上下文全部被保留了下来。
Lamda表达式:通俗点说,就是一个简单的闭包函数,通过表达式的方式来进行执行,而不需要再写复杂的逻辑指令式代码,或者无数的花括号来表明相关的上下文逻辑。这点对于简化繁杂的逻辑代码非常有帮助。
回调与改善的异步:其实,回调函数说实话也就是一个函数指针,也许很多人也用过,但是其实它的作用非行强大,如果你一直只接触过Java,C99的话是很难真正理解它对于IO或者网络请求的意义。尤其当你要处理多个异步事件流程,异常处理时,你就会发现它的真正意义。
其实,如果不是一定要从理论高度彻底理解函数式编程,没有必要从头看SICP或者所谓《21天精通Haskell》……(别打我),像Swift,C#,Java8,Python,C++11这种面向现代的语言中,都会有对于Lamda表达式的支持,像JavaScript这种更是纯粹可以当作函数式语言来写。所以,其实你已经在不知不觉中使用了函数式的一些思想,今天我就大概举几个例子来说明一下。
iOS开发中使用Swift来完成异步事件
异步事件编程,其实并不是什么新东西了,基本所有涉及到GUI的,网络请求的,数据库读写的,都会有它的身影。
异步事件,就是说这一个代码或者代码块,并不会阻塞程序的运行,程序会立即执行下一条语句,而这条语句,会在相应的方法调用结束之后,执行它自身的回调函数发送一些信号,来表明这个异步事件完成。就像你约会提前1小时到见面地点,先去买点东西踩点什么的(……),等GF/BF到了之后短信通知你,你就立即回来。而不是一直在原地等到对方过来(……)
最早使用异步开发,是在使用JavaScript来开发Web前端的时候,XMLHttpRequest或者jQuery的**$.ajax**中,都会用到回调函数,来指明成功或者失败之后的处理方法。当对应的网络请求得到响应之后,会调用响应的成功或者失败的回调函数,然后执行里面相应的方法,这大大提升了前端的效率,不会在网络请求时整个页面卡住,而且也不需要一次次轮询看是否有响应,简化了代码的复杂性。
这点Node.js中更为常见,不过也更能表现中滥用异步事件编程的问题。新人使用Node.js总会发现基本任何东西都是异步的,数据库是异步的,IO文件操作是异步的,Session读写是异步的,甚至获得Request对象都是异步的。这就导致很多人一直在嵌套回调函数,导致了著名的Callback Hell
在Node.js中,解决方案有非常成熟的Async,更有号称能用同步思维写异步的Promises,都是非常棒的解决方案。前者的本质就是一个自动生成回调的封装……,后者则是一个真正意义上的全新的解决方案。
而在Swift和iOS开发中,也有必须用到异步事件编程的地方。除了View层的简单UI和Controller之间的交互以外(这部分一般不需要手写代码处理异步交互或者顺序),其他很多地方需要这些知识。例如网络请求的异步调用,请求队列的处理(虽然可以一个网络请求就是一个线程,但这种方法的效率不高,而且容易导致线程间冲突),SQLite数据库大量数据的读写,本地存储的大量数据读写,复杂UI的渲染顺序等等……这些都是需要进行异步编程的,而不能让同步的代码阻塞住整个应用或者UI。
Autolayout小技巧
iOS开发UI一直是一个问题,当年用代码画UI一度成为流行趋势,相信代码能万能解决问题,而且十分简单。
然而,现在由于iOS设备的不断迭代,市场上常见的iPhone设备就会有:
iPhone4/4S 960640 (480320 @2x)
iPhone5/5S 1136640 (568320 @2x)
iPhone6 1334*750(667*375 @2x)
iPhone6 Plus 1920*1080(736*414 @3x)->(2208*1242)
加上iPad以后,还会有一个1024768(@1x) 和 20481536(@2x) 原来想要做一个自适应的,同时支持iPhone和iPad的应用,就算用代码来画UI,也是十分简单的。而现在,在这总共3类,5种,7状态的iOS设备面前,就会有点力不从心了,更别说以后想要做WatchOS的开发就会遇到很多问题,而Autolayout的解决方法的提出大大简化了这一过程
Autolayout,就是通过一系列的约束条件来控制一个UIView在视图中的位置,同时还要配合Size Classes(兼容iOS8之后的设备)
1、对于一个TableView,我们只需要设置它的Leading、Trailing、Top、Bottom临接到根View即可让它永远全屏显示,无论设备像素。而且,重要的一点,就是在Attribute Inspector中,要把这些距离设置为Standard(或者是0),这样才能在不同设备中获得推荐的显示效果(如果不是Standard或者0的话,就要小心了,这些就是所谓的魔法数字,很可能不同尺寸设备上显示效果会有所差别)
推荐一个Swift以及iOS开发的Git合集
地址在此:
https://github.com/ipader/SwiftGuide
里面包括但不限于这些内容:
- Swift语法
- Swift和Objective-C合作
- iOS开发
- Cocoa框架
- 设计模式
- 函数式编程思想
- 常用UI控件、库
- 实际Swift项目
喜欢的赶紧过去看看点个Star……重要的事情我只说一遍