Blog

告诉孩子他很聪明,最后却会让孩子感觉自己很愚蠢

Content #

在研究中,还有一个发现让我们感到既震惊又郁闷。我们对每个学生说:“你知道,我们现在要去其他学校,我相信其他学校的学生们也想了解一下这些题目。”所以我们给这些学生一张纸,让他们写下他们的感受,也让他们写下自己做这些题目时的分数。

让人难以置信的是,在那些能力被夸奖的学生当中,有将近40%的人谎报了成绩,而且都报高了!在固定型思维模式中,不完美是一件耻辱的事情,特别是当你被称作“有天赋”的时候,所以他们选择撒谎。

这为我们敲响了警钟——我们将普通的孩子变成了骗子,只是因为我们告诉他们,他们非常聪明。

就在写完上面这些话后,我见了一位年轻人,他的工作是辅导学生们准备大学委员会考试。他因为一个学生的情况来向我咨询。这名学生参加了模拟测试,但是向他谎报了成绩。这位年轻人本应该辅导该学生学习他不懂的内容,但这名学生却不肯告诉他自己的真实水平,她还是花钱来上他的辅导课的。

所以告诉孩子们他们很聪明,最后却会让他们感到自己很愚蠢,做出蠢事,但依然声称自己是聪明人。当我们把“有才能”“有天赋”“杰出”这些肯定的标签贴在孩子们身上时,我不认为这是我们想要的结果。我们并不想剥夺他们对挑战的热爱,阻碍他们掌握通往成功的秘诀,但我们的做法却带来了这些风险。

From #

终身成长

不同思维模式对学习的影响

Content #

在学期之初,我们测量了学生们的思维模式,之后跟随他们一起上课,观察他们的得分并询问他们的学习策略。我们再一次发现,具有成长型思维模式的学生在课程中取得了更高的分数。他们即使在某次特别的测验里表现得不好,下一次仍然会迎头赶上。而当具有固定型思维模式的学生考得不好的时候,他们基本上很难提高分数。

在这门课程中,每个人都很努力地学习,但学习方法却不尽相同。很多学生的学习方法是阅读课本和自己的课堂笔记。如果内容特别难,他们会再读一遍。他们也会尝试着把所有东西都背下来,就像吸尘器一样。这就是具有固定型思维模式的学生们的学习方法。他们如果考得不好,会得出结论,认为化学并不适合他们,毕竟,“我已经做了所有可以做的事,不是吗?”

事实远非如此。如果他们了解具有成长型思维模式的学生是如何学习的,他们一定会很震惊。甚至连我都觉得不同寻常。

具有成长型思维模式的学生完全掌控着自己的学习过程和动力。不是一头钻进书里,不动脑子地死记硬背,他们说,“我会寻找串联每个讲座的主题以及潜在规律”,还有“我不断重新审视自己的错误,直到我弄明白错在哪里”。他们学习的目标是获得知识,而不只是为了通过考试。而且,实际上,这也是他们会取得更好成绩的原因——并不是因为他们更聪明,或者拥有更好的理工科基础。

当课程变得困难和枯燥的时候,他们并没有失去动力,他们说:“我让自己对课程内容保持兴趣。”“我对上化学课保持积极的心态。”“我让自己保持学习的动力。”即使认为课程很无聊或者导师很无趣,他们也不会让自己的动力消失。

From #

终身成长

2PC的三大问题

Content #

相比于 TCC,2PC 的优点是借助了数据库的提交和回滚操作,不侵入业务逻辑。但是,它也存在一些明显的问题:

  1. 同步阻塞

执行过程中,数据库要锁定对应的数据行。如果其他事务刚好也要操作这些数据行,那它们就只能等待。其实同步阻塞只是设计方式,真正的问题在于这种设计会导致分布式事务出现高延迟和性能的显著下降。

  1. 单点故障

事务管理器非常重要,一旦发生故障,数据库会一直阻塞下去。尤其是在第二阶段发生故障的话,所有数据库还都处于锁定事务资源的状态中,从而无法继续完成事务操作。

  1. 数据不一致

在第二阶段,当事务管理器向参与者发送 Commit 请求之后,发生了局部网络异常,导致只有部分数据库接收到请求,但是其他数据库未接到请求所以无法提交事务,整个系统就会出现数据不一致性的现象。比如,小明的余额已经能够扣减,但是小红的余额没有增加,这样就不符合原子性的要求了。

Viewpoints #

From #

09|原子性:2PC还是原子性协议的王者吗?

随机超时时间的两种含义

Content #

在 Raft 算法中,随机超时时间是有 2 种含义的,需要注意一下:

  1. 跟随者等待领导者心跳信息超时的时间间隔,是随机的;

  2. 如果候选人在一个随机时间间隔内,没有赢得过半票数,那么选举无效了,然后候选人发起新一轮的选举,也就是说,等待选举超时的时间间隔,是随机的。

Viewpoints #

From #

07 | Raft算法(一):如何选举领导者?

Appending Images

将三个图片拼接成一个图片(垂直方向) #

convert -append input1.jpg input2.jpg input3.jpg output.jpg

为每个图片添加边界 #

convert -append input2.jpg input2.jpg input3.jpg -border 5 output.jpg

图片有大有小,拼接时设置背景色 #

convert -background red -append input1.jpg input2.jpg input3.jpg output.jpg

水平方向拼接三个图片 #

convert +append input1.jpg input2.jpg input3.jpg output.jpg 减号变加号。

击鼓传花

Content #

“击鼓传花”的游戏很多人都玩过,花从一个人手中传给另外一个人,就有点类似流水线的操作。这个花就是数据,花在游戏者之间流转,这就类似编程中的数据传递。

还记得上节课我给你留了一道任务编排的题吗?其实它就可以用数据传递的方式实现。

有 4 个 goroutine,编号为 1、2、3、4。每秒钟会有一个 goroutine 打印出它自己的编号,要求你编写程序,让输出的编号总是按照 1、2、3、4、1、2、3、 4……这个顺序打印出来。

为了实现顺序的数据传递,我们可以定义一个令牌的变量,谁得到令牌,谁就可以打印一次自己的编号,同时将令牌传递给下一个 goroutine,我们尝试使用 chan 来实现,可以看下下面的代码。

type Token struct{}

func newWorker(id int, ch chan Token, nextCh chan Token) {
    for {
        token := <-ch         // 取得令牌
        fmt.Println((id + 1)) // id从1开始
        time.Sleep(time.Second)
        nextCh <- token
    }
}
func main() {
    chs := []chan Token{make(chan Token), make(chan Token), make(chan Token), make(chan Token)}

    // 创建4个worker
    for i := 0; i < 4; i++ {
        go newWorker(i, chs[i], chs[(i+1)%4])
    }

    //首先把令牌交给第一个worker
    chs[0] <- struct{}{}

    select {}
}

首先,我们定义一个令牌类型(Token),接着定义一个创建 worker 的方法,这个方法会从它自己的 chan 中读取令牌。哪个 goroutine 取得了令牌,就可以打印出自己编号,因为需要每秒打印一次数据,所以,我们让它休眠 1 秒后,再把令牌交给它的下家。

接着,启动每个 worker 的 goroutine,并在第 20 行将令牌先交给第一个 worker。

...

使用反射操作Channel

Content #

select 语句可以处理 chan 的 send 和 recv,send 和 recv 都可以作为 case clause。如果我们同时处理两个 chan,就可以写成下面的样子:

select {
case v := <-ch1:
    fmt.Println(v)
case v := <-ch2:
    fmt.Println(v)
}

如果需要处理三个 chan,你就可以再添加一个 case clause,用它来处理第三个 chan。可是,如果要处理 100 个 chan 呢?一万个 chan 呢?

或者是,chan 的数量在编译的时候是不定的,在运行的时候需要处理一个 slice of chan,这个时候,也没有办法在编译前写成字面意义的 select。那该怎么办?

这个时候,就要“祭”出我们的反射大法了。

通过 reflect.Select 函数,你可以将一组运行时的 case clause 传入,当作参数执行。Go 的 select 是伪随机的,它可以在执行的 case 中随机选择一个 case,并把选择的这个 case 的索引(chosen)返回,如果没有可用的 case 返回,会返回一个 bool 类型的返回值,这个返回值用来表示是否有 case 成功被选择。如果是 recv case,还会返回接收的元素。Select 的方法签名如下:

func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool)

下面,我来借助一个例子,来演示一下,动态处理两个 chan 的情形。因为这样的方式可以动态处理 case 数据,所以,你可以传入几百几千几万的 chan,这就解决了不能动态处理 n 个 chan 的问题。

...

不愿努力综合症

Content #

所以也难怪,这么多青春期的学生绞尽脑汁,不为了学习,而是为了保护他们的自我意识。而他们达成这一目标的主要途径(除了对自己的老师进行生动的攻击外)就是放弃努力。正如我们之前提到的娜佳·萨莱诺-索南伯格这样聪明的学生,也在这个时间段放弃了努力。事实上,具有固定型思维模式的学生们告诉我们,他们在学校的主要目标除了让自己显得聪明以外,就是尽可能少付出努力。他们非常同意这样的说法:

“在学校里,我的主要目标就是尽可能简单地去做事情,这样我就不用太努力了。”

这种“不愿努力”综合症也经常被当作青少年与成年人划分界线的一种方式,但同时也是具有固定型思维模式的学生保护自己的一种途径。他们认为成年人在对他们说:“现在我要看看你到底有什么本事。”他们的回答是:“不,我是不会让你看到的。”

杰出的教育家约翰·霍尔特(John Holt)说,当其他人对自己品头论足的时候,我们都会使出这套招数。“我们那里最差的学生,我遇到过的最差的学生,在教室外的生活中和学校里其他同学一样成熟、聪明、有趣。到底是哪里出了问题?……在某一个环节上,他的智力水平和他的学校教育之间产生了脱节。”

而具有成长型思维模式的学生认为,停止努力是自己无法理解的一件事。对他们来说,青春期是一个充满了机遇的时期:在这个时期可以学习新的科目,可以找到他们的兴趣点,以及未来想要做什么。

From #

终身成长

进入初中后两种不同模式思维的学生的变化

Content #

进入初中的这种转变对很多学生来说都是一项很大的挑战。功课开始变得更难,评分也越来越严格,教学过程也不再那么有针对性。而学生们正在面对青春期带来的身体和角色上的转变,这一切都发生在同一时刻。他们的成绩开始变得糟糕,但不是所有人的成绩最终都会一落千丈。

确实不是这样的。在我们的研究里,只有具有固定型思维模式的学生会出现成绩下滑的情况。他们的成绩出现了突然的下降,并在接下来的两年里越来越差。而具有成长型思维模式的学生们在后来的两年里成绩逐步提高。

这两组学生刚进入初中时的成绩几乎一样。在教学气氛比较宽松的小学阶段,他们获得的评分和考试成绩没什么差别,但当他们在初中遇到挑战之后,两组学生的差距开始增加。

具有固定型思维模式的学生是这样解释他们糟糕的成绩的。有一些人会贬低自己的能力:“我是最笨的”或者“我被数学搞得头都大了”。还有很多人为了掩盖这种情绪,转而去责怪其他人:“因为数学老师又胖又讨厌”“因为英语老师是一个大屁股胖子”或者“因为老师嗑药了”。这些五花八门的分析问题的方式,让他们很难在未来获得成功。

面对失败逼近的威胁,具有成长型思维模式的学生们则动用他们的全部能力来学习。他们对我们说,自己有时也会感到招架不住,但他们采取的应对方式却是坚持不懈,全力以赴。他们就像乔治·丹齐格(George Dantzig)一样。丹齐格是谁?

丹齐格在加州大学伯克利分校数学系读研究生时,一天,他像往常一样,上数学课迟到了。他冲进教室后,抄下了黑板上的两道作业题。后来做作业的时候,他觉得这两道题非常难,花了很多天才解出来。最后他发现,原来这两道题根本不是作业,而是两道尚未解决的著名的数学难题。

From #

终身成长