Java 系列博客文章

【转载-阮一峰】CAP 定理的含义

分布式系统(distributed system)正变得越来越重要,大型网站几乎都是分布式的。

分布式系统的最大难点,就是各个节点的状态如何同步。CAP 定理是这方面的基本定理,也是理解分布式系统的起点。

本文介绍该定理。它其实很好懂,而且是显而易见的。下面的内容主要参考了 Michael Whittaker 的文章

一、分布式系统的三个指标

1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标。

Consistency Availability Partition tolerance

它们的第一个字母分别是 C、A、P。

Eric Brewer 说,这三个指标不可能同时做到。这个结论就叫做 CAP 定理。

二、Partition tolerance

先看 Partition tolerance,中文叫做"分区容错"。

大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition)。分区容错的意思是,区间通信可能失败。比如,一台服务器放在中国,另一台服务器放在美国,这就是两个区,它们之间可能无法通信。

上图中,G1 和 G2 是两台跨区的服务器。G1 向 G2 发送一条消息,G2 可能无法收到。系统设计的时候,必须考虑到这种情况。

一般来说,分区容错无法避免,因此可以认为 CAP 的 P 总是成立。CAP 定理告诉我们,剩下的 C 和 A 无法同时做到。

三、Consistency

Consistency 中文叫做"一致性"。意思是,写操作之后的读操作,必须返回该值。举例来说,某条记录是 v0,用户向 G1 发起一个写操作,将其改为 v1。

接下来,用户的读操作就会得到 v1。这就叫一致性。

问题是,用户有可能向 G2 发起读操作,由于 G2 的值没有发生变化,因此返回的是 v0。G1 和 G2 读操作的结果不一致,这就不满足一致性了。

为了让 G2 也能变为 v1,就要在 G1 写操作的时候,让 G1 向 G2 发送一条消息,要求 G2 也改成 v1。

这样的话,用户向 G2 发起读操作,也能得到 v1。

四、Availability

Availability 中文叫做"可用性",意思是只要收到用户的请求,服务器就必须给出回应。

用户可以选择向 G1 或 G2 发起读操作。不管是哪台服务器,只要收到请求,就必须告诉用户,到底是 v0 还是 v1,否则就不满足可用性。

五、Consistency 和 Availability 的矛盾

一致性和可用性,为什么不可能同时成立?答案很简单,因为可能通信失败(即出现分区容错)。

如果保证 G2 的一致性,那么 G1 必须在写操作时,锁定 G2 的读操作和写操作。只有数据同步后,才能重新开放读写。锁定期间,G2 不能读写,没有可用性不。

如果保证 G2 的可用性,那么势必不能锁定 G2,所以一致性不成立。

综上所述,G2 无法同时做到一致性和可用性。系统设计时只能选择一个目标。如果追求一致性,那么无法保证所有节点的可用性;如果追求所有节点的可用性,那就没法做到一致性。

[更新 2018.7.17]

读者问,在什么场合,可用性高于一致性?

举例来说,发布一张网页到 CDN,多个服务器有这张网页的副本。后来发现一个错误,需要更新网页,这时只能每个服务器都更新一遍。

一般来说,网页的更新不是特别强调一致性。短时期内,一些用户拿到老版本,另一些用户拿到新版本,问题不会特别大。当然,所有人最终都会看到新版本。所以,这个场合就是可用性高于一致性。

(完)

【转载】http://www.ruanyifeng.com/blog/2018/07/cap.html

read more

Linux、网络相关

linux内存映射mmap原理分析

内存映射,简而言之就是将用户空间的一段内存区域映射到内核空间,映射成功后,用户对这段内存区域的修改可以直接反映到内核空间,同样,内核空间对这段区域的修改也直接反映用户空间。那么对于内核空间<---->用户空间两者之间需要大量数据传输等操作的话效率是非常高的。

二、基本函数

mmap函数是unix/linux下的系统调用,详细内容可参考《Unix Netword programming》卷二12.2节。

mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一。

mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。mmap并不分配空间, 只是将文件映射到调用进程的地址空间里(但是会占掉你的 virutal memory), 然后你就可以用memcpy等操作写文件, 而不用write()了.写完后,内存中的内容并不会立即更新到文件中,而是有一段时间的延迟,你可以调用msync()来显式同步一下, 这样你所写的内容就能立即保存到文件里了.这点应该和驱动相关。 不过通过mmap来写文件这种方式没办法增加文件的长度, 因为要映射的长度在调用mmap()的时候就决定了.如果想取消内存映射,可以调用munmap()来取消内存映射。

void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)

mmap用于把文件映射到内存空间中,简单说mmap就是把一个文件的内容在内存里面做一个映像。映射成功后,用户对这段内存区域的修改可以直接反映到内核空间,同样,内核空间对这段区域的修改也直接反映用户空间。那么对于内核空间<---->用户空间两者之间需要大量数据传输等操作的话效率是非常高的。

原理

首先,“映射”这个词,就和数学课上说的“一一映射”是一个意思,就是建立一种一一对应关系,在这里主要是只 硬盘上文件 的位置与进程 逻辑地址空间 中一块大小相同的区域之间的一一对应,如图1中过程1所示。这种对应关系纯属是逻辑上的概念,物理上是不存在的,原因是进程的逻辑地址空间本身就是不存在的。在内存映射的过程中,并没有实际的数据拷贝,文件没有被载入内存,只是逻辑上被放入了内存,具体到代码,就是建立并初始化了相关的数据结构(struct address_space),这个过程有系统调用mmap()实现,所以建立内存映射的效率很高。

图1.内存映射原理

既然建立内存映射没有进行实际的数据拷贝,那么进程又怎么能最终直接通过内存操作访问到硬盘上的文件呢?那就要看内存映射之后的几个相关的过程了。

mmap()会返回一个指针ptr,它指向进程逻辑地址空间中的一个地址,这样以后,进程无需再调用read或write对文件进行读写,而只需要通过ptr就能够操作文件。但是ptr所指向的是一个逻辑地址,要操作其中的数据,必须通过MMU将逻辑地址转换成物理地址,如图1中过程2所示。这个过程与内存映射无关。

前面讲过,建立内存映射并没有实际拷贝数据,这时,MMU在地址映射表中是无法找到与ptr相对应的物理地址的,也就是MMU失败,将产生一个缺页中断,缺页中断的中断响应函数会在swap中寻找相对应的页面,如果找不到(也就是该文件从来没有被读入内存的情况),则会通过mmap()建立的映射关系,从硬盘上将文件读取到物理内存中,如图1中过程3所示。这个过程与内存映射无关。

如果在拷贝数据时,发现物理内存不够用,则会通过虚拟内存机制(swap)将暂时不用的物理页面交换到硬盘上,如图1中过程4所示。这个过程也与内存映射无关。

效率

从代码层面上看,从硬盘上将文件读入内存,都要经过文件系统进行数据拷贝,并且数据拷贝操作是由文件系统和硬件驱动实现的,理论上来说,拷贝数据的效率是一样的。但是通过内存映射的方法访问硬盘上的文件,效率要比read和write系统调用高,这是为什么呢?原因是read()是系统调用,其中进行了数据拷贝,它首先将文件内容从硬盘拷贝到内核空间的一个缓冲区,如图2中过程1,然后再将这些数据拷贝到用户空间,如图2中过程2,在这个过程中,实际上完成了 两次数据拷贝 ;而mmap()也是系统调用,如前所述,mmap()中没有进行数据拷贝,真正的数据拷贝是在缺页中断处理时进行的,由于mmap()将文件直接映射到用户空间,所以中断处理函数根据这个映射关系,直接将文件从硬盘拷贝到用户空间,只进行了 一次数据拷贝 。因此,内存映射的效率要比read/write效率高。

图2.read系统调用原理

下面这个程序,通过read和mmap两种方法分别对硬盘上一个名为“mmap_test”的文件进行操作,文件中存有10000个整数,程序两次使用不同的方法将它们读出,加1,再写回硬盘。通过对比可以看出,read消耗的时间将近是mmap的两到三倍。

#include<unistd.h> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/types.h> #include<sys/stat.h> #include<sys/time.h> #include<fcntl.h> #include<sys/mman.h> #define MAX 10000 int main() { int i=0; int count=0, fd=0; struct timeval tv1, tv2; int *array = (int *)malloc( sizeof(int)*MAX ); /*read*/ gettimeofday( &tv1, NULL ); fd = open( "mmap_test", O_RDWR ); if( sizeof(int)*MAX != read( fd, (void *)array, sizeof(int)*MAX ) ) { printf( "Reading data failed.../n" ); return -1; } for( i=0; i<MAX; ++i ) ++array[ i ]; if( sizeof(int)*MAX != write( fd, (void *)array, sizeof(int)*MAX ) ) { printf( "Writing data failed.../n" ); return -1; } free( array ); close( fd ); gettimeofday( &tv2, NULL ); printf( "Time of read/write: %dms/n", tv2.tv_usec-tv1.tv_usec ); /*mmap*/ gettimeofday( &tv1, NULL ); fd = open( "mmap_test", O_RDWR ); array = mmap( NULL, sizeof(int)*MAX, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ); for( i=0; i<MAX; ++i ) ++array[ i ]; munmap( array, sizeof(int)*MAX ); msync( array, sizeof(int)*MAX, MS_SYNC ); free( array ); close( fd ); gettimeofday( &tv2, NULL ); printf( "Time of mmap: %dms/n", tv2.tv_usec-tv1.tv_usec ); return 0; }

输出结果:

Time of read/write: 154ms

Time of mmap: 68ms

原文:https://blog.csdn.net/mg0832058/article/details/5890688

read more
MySQL的InnoDB的幻读问题

MySQL InnoDB事务的隔离级别有四级,默认是“可重复读”(REPEATABLE READ)。

未提交读(READ UNCOMMITTED)。另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据(脏读)。 提交读(READ COMMITTED)。本事务读取到的是最新的数据(其他事务提交后的)。问题是,在同一个事务里,前后两次相同的SELECT会读到不同的结果(不重复读)。 可重复读(REPEATABLE READ)。在同一个事务里,SELECT的结果是事务开始时时间点的状态,因此,同样的SELECT操作读到的结果会是一致的。但是,会有幻读现象(稍后解释)。 串行化(SERIALIZABLE)。读操作会隐式获取共享锁,可以保证不同事务间的互斥。

四个级别逐渐增强,每个级别解决一个问题。

脏读,最容易理解。另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据。 不重复读。解决了脏读后,会遇到,同一个事务执行过程中,另外一个事务提交了新数据,因此本事务先后两次读到的数据结果会不一致。 幻读。解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。但是,如果另一个事务同时提交了新数据,本事务再更新时,就会“惊奇的”发现了这些新数据,貌似之前读到的数据是“鬼影”一样的幻觉。

借鉴并改造了一个搞笑的比喻:

脏读。假如,中午去食堂打饭吃,看到一个座位被同学小Q占上了,就认为这个座位被占去了,就转身去找其他的座位。不料,这个同学小Q起身走了。事实:该同学小Q只是临时坐了一小下,并未“提交”。 不重复读。假如,中午去食堂打饭吃,看到一个座位是空的,便屁颠屁颠的去打饭,回来后却发现这个座位却被同学小Q占去了。 幻读。假如,中午去食堂打饭吃,看到一个座位是空的,便屁颠屁颠的去打饭,回来后,发现这些座位都还是空的(重复读),窃喜。走到跟前刚准备坐下时,却惊现一个恐龙妹,严重影响食欲。仿佛之前看到的空座位是“幻影”一样。

一些文章写到InnoDB的可重复读避免了“幻读”(phantom read),这个说法并不准确。

做个试验:(以下所有试验要注意存储引擎和隔离级别)

mysql> show create table t_bitfly\G;
CREATE TABLE t_bitfly (
id bigint(20) NOT NULL default '0',
value varchar(32) default NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=gbk

mysql> select @@global.tx_isolation, @@tx_isolation;
+-----------------------+-----------------+
| @@global.tx_isolation | @@tx_isolation  |
+-----------------------+-----------------+
| REPEATABLE-READ       | REPEATABLE-READ |
+-----------------------+-----------------+

试验一:

t Session A                                   Session B
|
| START TRANSACTION;            START TRANSACTION;
|
| SELECT * FROM t_bitfly;
| empty set
|                                                             INSERT INTO t_bitfly
|                                                             VALUES (1, 'a');
|
| SELECT * FROM t_bitfly;
| empty set
|                                                             COMMIT;
|
| SELECT * FROM t_bitfly;
| empty set
|
| INSERT INTO t_bitfly VALUES (1, 'a');
| ERROR 1062 (23000):
| Duplicate entry '1' for key 1
v (shit, 刚刚明明告诉我没有这条记录的)

如此就出现了幻读,以为表里没有数据,其实数据已经存在了,傻乎乎的提交后,才发现数据冲突了。

试验二:

t Session A                                     Session B
|
| START TRANSACTION;              START TRANSACTION;
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|                                                            INSERT INTO t_bitfly
|                                                            VALUES (2, 'b');
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|                                                            COMMIT;
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|
| UPDATE t_bitfly SET value='z';
| Rows matched: 2  Changed: 2  Warnings: 0
| (怎么多出来一行)
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | z     |
| |    2 | z     |
| +------+-------+
|
v

本事务中第一次读取出一行,做了一次更新后,另一个事务里提交的数据就出现了。也可以看做是一种幻读。

那么,InnoDB指出的可以避免幻读是怎么回事呢?

http://dev.mysql.com/doc/refman/5.0/en/innodb-record-level-locks.html

By default, InnoDB operates in REPEATABLE READ transaction isolation level and with the innodb_locks_unsafe_for_binlog system variable disabled. In this case, InnoDB uses next-key locks for searches and index scans, which prevents phantom rows (see Section 13.6.8.5, “Avoiding the Phantom Problem Using Next-Key Locking”).

准备的理解是,当隔离级别是可重复读,且禁用innodb_locks_unsafe_for_binlog的情况下,在搜索和扫描index的时候使用的next-key locks可以避免幻读。

关键点在于,是InnoDB默认对一个普通的查询也会加next-key locks,还是说需要应用自己来加锁呢?如果单看这一句,可能会以为InnoDB对普通的查询也加了锁,如果是,那和序列化(SERIALIZABLE)的区别又在哪里呢?

MySQL manual里还有一段:

13.2.8.5. Avoiding the Phantom Problem Using Next-Key Locking (http://dev.mysql.com/doc/refman/5.0/en/innodb-next-key-locking.html)

To prevent phantoms, InnoDB uses an algorithm called next-key locking that combines index-row locking with gap locking.

You can use next-key locking to implement a uniqueness check in your application: If you read your data in share mode and do not see a duplicate for a row you are going to insert, then you can safely insert your row and know that the next-key lock set on the successor of your row during the read prevents anyone meanwhile inserting a duplicate for your row. Thus, the next-key locking enables you to “<span style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px;">lock</span>” the nonexistence of something in your table.

我的理解是说,InnoDB提供了next-key locks,但需要应用程序自己去加锁。manual里提供一个例子:

SELECT * FROM child WHERE id > 100 FOR UPDATE;

这样,InnoDB会给id大于100的行(假如child表里有一行id为102),以及100-102,102+的gap都加上锁。

可以使用show innodb status来查看是否给表加上了锁。

再看一个实验,要注意,表t_bitfly里的id为主键字段。实验三:

t Session A                                       Session B
|
| START TRANSACTION;                START TRANSACTION;
|
| SELECT * FROM t_bitfly
| WHERE id<=1
| FOR UPDATE;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|                                                           INSERT INTO t_bitfly
|                                                           VALUES (2, 'b');
|                                                           Query OK, 1 row affected
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|                                                           INSERT INTO t_bitfly
|                                                           VALUES (0, '0');
|                                                           (waiting for lock ...
|                                                           then timeout)
|                                                           ERROR 1205 (HY000):
|                                                           Lock wait timeout exceeded;
|                                                           try restarting transaction
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
|                                                           COMMIT;
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id   | value |
| +------+-------+
| |    1 | a     |
| +------+-------+
v

可以看到,用id<=1加的锁,只锁住了id<=1的范围,可以成功添加id为2的记录,添加id为0的记录时就会等待锁的释放。

MySQL manual里对可重复读里的锁的详细解释:

http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read

For locking reads (SELECT with FOR UPDATE or LOCK IN SHARE MODE),UPDATE, and DELETE statements, locking depends on whether the statement uses a unique index with a unique search condition, or a range-type search condition. For a unique index with a unique search condition, InnoDB locks only the index record found, not the gap before it. For other search conditions, InnoDB locks the index range scanned, using gap locks or next-key (gap plus index-record) locks to block insertions by other sessions into the gaps covered by the range.

一致性读和提交读,先看实验,实验四:

t Session A                                                    Session B
|
| START TRANSACTION;                             START TRANSACTION;
|
| SELECT * FROM t_bitfly;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| +----+-------+
|                                                                        INSERT INTO t_bitfly
|                                                                                VALUES (2, 'b');
|                                                                        COMMIT;
|
| SELECT * FROM t_bitfly;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| +----+-------+
|
| SELECT * FROM t_bitfly LOCK IN SHARE MODE;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| |  2 | b     |
| +----+-------+
|
| SELECT * FROM t_bitfly FOR UPDATE;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| |  2 | b     |
| +----+-------+
|
| SELECT * FROM t_bitfly;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| +----+-------+
v

如果使用普通的读,会得到一致性的结果,如果使用了加锁的读,就会读到“最新的”“提交”读的结果。

本身,可重复读和提交读是矛盾的。在同一个事务里,如果保证了可重复读,就会看不到其他事务的提交,违背了提交读;如果保证了提交读,就会导致前后两次读到的结果不一致,违背了可重复读。

可以这么讲,InnoDB提供了这样的机制,在默认的可重复读的隔离级别里,可以使用加锁读去查询最新的数据。

http://dev.mysql.com/doc/refman/5.0/en/innodb-consistent-read.html

If you want to see the “freshest” state of the database, you should use either the READ COMMITTED isolation level or a locking read:
SELECT * FROM t_bitfly LOCK IN SHARE MODE;

结论:MySQL InnoDB的可重复读并不保证避免幻读,需要应用使用加锁读来保证。而这个加锁度使用到的机制就是next-key locks。

==================== 结尾 ====================

作者: bitfly. 转载请注明来源或包含本信息. 谢谢
链接: http://blog.bitfly.cn/post/mysql-innodb-phantom-read/

read more
APK反编译总结
1.准备环境

win7
android-sdk_r24.0.2-windows.zip
jdk7
android studio1.5
eclipse
charles

温馨提示:后面三个工具都需要jre|jdk环境,请首先安装jdk.

2.抓包过程

通过在PC端安装charles软件,android端设置网络代理,抓取网络数据包。

2.1、PC端:在pc端创建wifi热点共享给外设->CMD命令行

netsh wlan set hostednetwork mode=allow ssid=abcd key=abcd1234

选择正在使用的网络连接,右键共享->勾选并选择刚刚创建的热点连接

netsh wlan start hostednetwork

charles:proxy setting 设置代理端口,若需https抓包请设置ssl选项,并且客户端安装charles证书

2.2、客户端:WLAN设置刚创建的“abcd”共享,并指定代理IP和端口号(自己ipconfig查看即可)

3.准备反编译工具

主要针对jvm的class文件和android虚拟机字节码smali,所需软件如下:

apktool_2.0.0rc4.zip ---- 可以得到apk里的资源和smali文件 dex2jar-2.0.zip ---- 获得class文件 jd-gui.exe ---- 反解class文件 signapk.rar ---- 修改smali或者资源文件,重新打包签名,***DEBUG*** 4.开始吧

这里以反编译土豆 app为例:

得到res和smali

java -jar apktool.jar d -d ..\..\youku\tudou\tudoushipin_61.apk -o ..\..\youku\tudou\tudoushipin_61

得到class

dex2jar.bat tudoushipin_61.apk

对上面的class使用jd-gui反编译,并导入eclipse

5.上演调试 && android studio

将smali文件导入到android studio

5.1、找到刚才apktool反解的目录找到AndroidManifest.xml,LAUNCHER对应的Activity标签上加入可被debug的配置android:debuggable="true",并保存。

5.2、假设我们现在把断点加载app的启动入口:
找到APK的入口Activity类(搜索关键字LAUNCHER你懂得),也就是:com.tudou.ui.activity.WelcomeActivity。

到了关键性的一步,找到这个Activity对应的smali文件;
定位到入口方法:onCreate;
在下面加入DEBUG代码,app启动时加入断点会停在这个位置;
说明一下:这段代码是smali的语法更多了解可以自行Google,OK。

a=0;// invoke-static {}, Landroid/os/Debug;->waitForDebugger()V

说明:根据你的需要可以把断点加到任意位置,前提是你要知道它在对应的smali文件的哪一行:方法是拿反编译后的Java文件和smali对应着去看,然后再找;后面的DEBUG也是这个思路(剧透)。

5.3、对修改后的apk重新打包

i.重新打包:

java -jar apktool.jar b -d ..\..\youku\tudou\tudoushipin_61 -o debug-tudou.apk

ii.重新签名:

java -jar signapk\signapk.jar signapk\testkey.x509.pem signapk\testkey.pk8 debug-tudou.apk debug-tudou.sign.apk

iii.一切可能都不是那么顺利):(

5.4、开启android studio-->基于知名的IntelliJ IDEA开发

1.导入之前反编译得到的smali文件到android studio,并在‘前面加debug代码’的地方加入断点。
2.找一部android手机(模拟器就算了,又慢又总是不兼容),安装刚才的签名后的apk,通过USB数据线接入PC。

5.5、有一些必要的说明

1.默认安装完android studio,例如:C:\dev\android\sdk
2.对于android Dalvik虚拟机的调试监控,DDMS已经被废弃了,新的是tools下的monitor工具,将其启动
3.在monitor中会看到devices中会出现小手机图标,端口号一般是8600

6.开始远程调试

1.android studio中菜单栏->RUN->Edit Configuration -> Remote(这根在eclipse中差不多)
指定host:localhost,端口:8600,module:smali所在的位置
启动app-->运行debug即可 -> 顺利的话光标会定位到你刚才的断点处。

2.观察Android Monitor窗口
观察Debugger tag,可以查看对象和变量的值

@hell 分享

read more

交流讨论专区,各种水~

团队文化价值观

认知、理解、判断或抉择,也就是人认定事物、辩定是非的一种思维或取向。

价值观是什么?我个人理解是一个人对事物的认知、理解,然后辨别是非的一种思维取向。而对于一个团队来说,团队所有成员共同的价值取向,以及在工作过程中遵循的基本信念和奉行的目标则是一个团队的文化价值观念。它是团队成员各项行为的准则,是凝聚团队的力量,也是团队向前的动力所在。比如 “主动敢担当、坚持再改变”,又如 “坦诚、协作、担当、进取”。

1、团队文化价值观的提法?

我认为和公司的价值观保持一致即可,坦诚、协作、担当、进取。只是不同的业务部门会针对企业核心价值观有更恰当的侧重点和发散方向。

2、如何落地?我对技术人员的几点看法。

坦诚:
从个人来讲,要善于发现自己的问题,并及时告知,然后解决;
从团队来讲,要与产品、运营同学沟通,尽可能保证信息对称,不能随意评估开发工期,故意拖延。

协作:
个人在技术开发遇到困难时,如果花费很多时间还未解决,应该及时求助其他同事帮助解决;被其他同事寻求帮助时,应该积极友善的去帮助别人;
在团队中,要积极参加产品头脑风暴,贡献idea,和产品、运营同学精诚协作,换位思考,不能随便砍需求,正确评估需求合理性;

担当:
自己遇到棘手、繁琐的任务时,应该积极主动的承担下来;
对自己的代码负责,不让其他同事承担自己的技术债。

进取:
不断学习新技术、在个人成长方面制定长期目标;
在团队、公司进行技术学习分享,提高自己的技术和团队的技术实力。最终达到个人团队共同成长,相互促进。

3、团队文化价值观能否在团队中产生作用?

我认为答案是不证自明的。

举个最接地气的例子,关于考勤,每天让我坚持起床上班不迟到的原因是什么?当然是价值观,肯定不是因为被帅醒。

因为我认为准时上班是一个合格员工应该也必须遵循的基本准则,这就是价值观的能动作用。

团队每个人如果都能从更深层次来解读和运用我们的价值观,那么我想,至少不会有迟到这样的问题。

当然,考勤只是我们的底线。作为一个成熟的企业员工,我们应该把团队价值观内化为我们的行为准则并身体力行。

有了团队价值观,即使遇到再难的项目,它都能够激发我们的动力并指引我们去完成,例如,为了一个项目能按时完成,我们可以加班加点;为了能想出更好的解决问题的办法,我们可以不眠不休的进行亢奋、激烈的讨论,为一个完美的方案,极尽所能地发散思维。

同时,团队的文化价值观不仅仅作为指引每一个人前进的灯塔,也是限制我们行为的轨道,在难以抉择的时候,让我们知道应该如何选择,知道什么能干什么不能干。

所有以上都潜移默化的在我们的工作中,并产生持久而稳定的影响,最终促进个人,团队的协同发展。

最后,我们应该在心里时刻提醒自己 “丰碑无语,行胜于言” 。

read more
Solidity IDE Remix中文版
E

Remix是以太坊官方开源的Solidity在线集成开发环境,可以使用Solidity语言在网页内完成以太坊智能合约的在线开发、在线编译、在线测试、在线部署、在线调试与在线交互,非常适合Solidity智能合约的学习与原型快速开发。

Solidity IDE中文版Remix由汇智网提供,国内CDN加速,访问地址:http://remix.hubwiz.com

如果要快速掌握以太坊智能合约与DApp开发,推荐汇智网的以太坊开发系列教程

Solidity IDE Remix为左中右三栏布局,左面板为Remix文件管理器,中间为文件编辑器,
右侧为开发工具面板:

1、Solidity IDE Remix文件管理器

Remix左面板中的文件管理器,用来列出在浏览器本地存储中保存的文件,分为browser和config两个目录,
当你第一次访问Remix的时候,在browser目录下有两个预置的代码:ballot.sol合约以及对应的单元测试
文件ballot_test.sol,点击文件名就可以在中间的文件编辑器中查看并编辑代码:

Remix文件管理器顶部的工具栏提供创建新文件、上传本地文件、发布gist等快捷功能,你可以将鼠标移到
相应的图标处停顿,然后查看功能的浮动提示信息。

为了后续功能的学习,你可以点击左上角的+创建一个新的solidity合约文件,在弹出的对话框中,将
文件命名为hello.sol:

点击[ok]按钮后,你就可以看到在左面板的文件管理其中browser目录下出现了hello.sol文件名,
同时在中间区域的文件编辑器中自动打开了这个新创建的文件等待编辑,现在它还是空的,我们将在下面
编写简单的Solidity代码。

2、Solidity IDE Remix编辑器及终端

Solidity IDE Remix中间区域为上下布局,分别提供文件编辑功能和终端访问功能。

2.1 Remix文件编辑器

Solidity IDE Remix中间区域上方的文件编辑器支持同时打开多个文件,当前激活的文件,其文件名以粗体显示:

Remix文件编辑器顶部左右两侧的箭头,分别用来切换左右面板的显示与隐藏;左上角的+和-,
分别用来放大或缩小编辑器里的文本字体大小。

现在我们激活hello.sol文件,然后输入简单的合约代码:

pragma solidity ^0.5.1; contract Hello{ function echo(string memory text) public pure returns(string memory) { return text; } }

基本上这是最简单的以太坊合约了,它只有一个echo()方法,作用就是把输入的字符串
再原样返回。

2.2 Remix终端

Solidity IDE Remix中间区域下方为终端,可以输入JavaScript命令与Remix IDE或区块链节点交互:

Remix终端内置了web3.js 1.0.0、ether.js、swarmgy以及当前载入的Solidity编译器,因此你可以
在终端内使用熟悉的web3 API与当前连接的区块链节点交互。

Remix终端同时也内置了remix对象,可以利用它来脚本化地操作Solidity Remix IDE,例如载入指定
url的gist,或者执行当前显示的代码。将终端显示向上滚动到开始位置,就可以看到remix对象的
常用方法描述。

Remix终端的另一个作用是显示合约执行或静态分析的运行结果。例如,当你部署一个合约后或执行
一个合约方法后,就会在终端看到它的执行信息:

点击信息行右侧的下拉图标,就可以查看该信息的详情;点击[debug]按钮,就会打开右侧面板中的
调试页对合约进行单步或断点调试。

Remix终端顶部的工具栏提供了切换终端显示状态、清理终端输出等功能,显示待定交易的量,
选择监听交易的范围,也可以搜索历史交易。

3、Solidity IDE Remix功能面板

Solidity IDE Remix的右侧为功能面板,以选项页的方式提供编译、运行、静态分析、测试、
调试、设置和技术支持功能。

3.1 编译选项页

在编译选项页,你可以点击下拉框切换当前要使用的Solidity编译器版本:

然后点击[开始编译]按钮,就会编译Remix文件编辑器中当前选中的代码文件,比如我们的
hello.sol文件。编译完成后,如果没有编译错误,就可以看到合约名字Hello出现在编译
选项页的合约下拉框中:

可以点击[swarm]按钮将编译好的合约上传到Swarm网络,或者点击[详情]按钮查看编译
结果详情,也可以点击[ABI]或[字节码]按钮,分别将合约的ABI与字节码拷贝到系统剪切板
以便在其他程序中使用。

3.2 运行选项页

在运行选项页,可以部署编译好的合约,也可以执行已部署合约的方法:

节点环境选项提供三种选择:JS虚拟机、注入Web3对象或使用web3提供器。

JS虚拟机是一个JS版本的以太坊虚拟机实现,它运行在你的浏览器内,因此你不需要考虑
节点配置或者担心损失以太币,最适合学习和快速原型验证。 如果你的浏览器安装了Metamask插件,或者使用Mist之类的以太坊兼容浏览器,那么也
可以选择第二个环境:使用注入的Web3对象。 如果你有自己的节点,那么可以选择第三个选项使用web3提供器来让Remix连接
到你的节点上,不过如果要连接的节点是接入以太坊主网的,要注意每一次交易都是
有成本的!

如果之前有编译好的合约,在运行选项页就可以看到这个合约的名字,例如我们的Hello。
点击[部署]按钮就可以将这个合约部署到我们选定的节点环境了:

现在可以看到,已部署的合约区域,已经出现我们的合约了。点击这个合约实例,
可以看到我们为Hello合约定义的echo方法自动显示出来了:

在方法名后面的输入框里输入方法参数,例如"helloooooooooooooo",然后点击方法名,
就可以执行合约的方法了:

你看到,返回值的确和我们输入的参数是一样的,我们实现了预定目标!

3.3 其他选项页

Solidity Remix集成开发环境还有很多功能值得研究,这个工作留给你自己了。我们只对其他
的选项页做简单介绍:

分析选项页提供对Solidity合约代码的静态分析选项。 测试选项页提供单元测试能力,你可以生成一个测试文件,或者执行一组测试。 调试器选项页可以单步跟踪合约的执行、查看合约状态或局部变量等。 设置选项提供Solidity Remix IDE本身的一些参数调整能力,例如设置编辑器文本自动折行、
启用插件、设置gist访问令牌,或者切换Remix IDE的皮肤主题 —— 目前只有三个:浅色、深色和净色。

原文:Solidity IDE Remix中文版 - 汇智网

read more
2019-02-26 听力打卡《参观自由女神像》

链接:https://dict.eudic.net/webting/desktopplay?id=0aa666b0-148d-11e9-8449-000c29ffef9b&token=QYN+eyJ0b2tlbiI6IiIsInVzZXJpZCI6IiIsInVybHNpZ24iOiJuOEc3d05JUmIxYlhsK3dFdzRQSXVVNnZzaVk9IiwidCI6IkFCSU1UVTNNRGt4TmpFM09BPT0ifQ%3D%3D

Ladies and Gentlemen, this is the Statue of Liberty , it's one of the American symbols.
It's really spectacular.
The statue has for a century acted as a figurehead for the American Dream.
I think we can climb to the top, Can't we ?
Of course you can.

词串:

spectacular
英 /spek'tækjʊlə/ 美 /spɛk'tækjəlɚ/ adj. 壮观的,惊人的;公开展示的 has for a century / have for a century
已经有一个世纪了 acted as a figurehead for American Dream.
被认为是美国梦的象征。 climb to
爬到

复习:
2019-02-28

read more