论坛首页 Java企业应用论坛

吹牛:我写的JSONParser可能是这个星球上最快了(Java)

浏览 143284 次
该帖已经被评为精华帖
作者 正文
   发表时间:2010-12-22  
看大牛们吹的漫天都是牛!
0 请登录后投票
   发表时间:2010-12-22   最后修改:2010-12-22
序列化和反序列化接口初步定义如下:

各部分的结构初步设计完毕,已经考虑了目前已知的各种扩展,大致如下:

public abstract class JSON {
	public static Object parse(String text);
	
	public static JSONObject parseObject(String text);
	public static JSONArray parseArray(String text);
	
	public static <T> List<T> parseArray(Class<T> clazz, String text);
	public static <T> T parseObject(Class<T> clazz, String text);
	
	public static String toJSONString(Object object); // 输出JSON String
	public static String toJSONString(Object object, boolean prettyFormat); // 可选格式化输出JSON String
	public static String toJSONString(Object object, JavaBeanHandler javaBeanHandler); // 使得可以对JavaBean做特别处理
	public static String toJSONStringEx(Object object) { // 使用CGLib实现JavaBean的序列化
		return toJSONString(object, false, CGLibJavaBeanHandler.getInstance());
	}
}

public interface JSONAware {
	String toJSONString();
}

public interface JSONStreamAware {
	void writeJSONString(Appendable out);
}

public class JSONArray extends JSON implements List<Object>, JSONAware {
	// ...
}

public class JSONObject extends JSON implements Map<String, Object>, JSONAware {
	// ...
}

public interface JSONParser {
	Object parse();
	void parseArray(Collection array);
	void parseObject(Map object);
}

// 使用可以扩展JSONParser,使得能够JSONString -> JavaBean,不需要额外的步骤
public interface ExtJSONParser extends JSONParser {
	void parseObject(Object object);
	<T> T parseObject(Class<T> clazz);
	
	void parseArray(Class<?> clazz, Collection array);
}

public class DefaultJSONParser implements JSONParser {
	// ...
}

public class CGLibExtJSONParser extends DefaultJSONParser implements ExtJSONParser {
	// ...
}

public interface JSONVisitor {
	JavaBeanHandler getJavaBeanHandler();

	void setJavaBeanHandler(JavaBeanHandler javaBeanHandler);

	void accept(Object object);

	void acceptBean(JSONAware javaBean);

	void acceptBean(JSONStreamAware javaBean);

	void acceptBean(Object javaBean);

	void acceptNull();

	void acceptValue(Date value);

	void acceptValue(Number value);

	void acceptValue(String value);

	void acceptValue(Boolean value);

	void acceptKey(String key);

	void acceptArray(Collection<?> array);

	void acceptObject(Map<?, ?> object);

	void acceptEntry(Map.Entry<?, ?> entry);

	void visitBean(JSONStreamAware object);

	void endVisitBean(JSONStreamAware object);

	void visitBean(JSONAware object);

	void endVisitBean(JSONAware object);

	void visitBean(Object object);

	void endVisitBean(Object object);

	boolean visitObject(Map<?, ?> map);

	void endVisitObject(Map<?, ?> map);

	boolean visitEntry(Map.Entry<?, ?> entry);

	void endVisitEntry(Map.Entry<?, ?> entry);

	boolean visitArray(Collection<?> array);

	void endVisitArray(Collection<?> array);

	void visitValue(Number value);

	void endVisitValue(Number value);

	void visitValue(Date value);

	void endVisitValue(Date value);

	void visitValue(boolean value);

	void endVisitValue(boolean value);

	void visitValue(String value);

	void endVisitValue(String value);

	void visitNull();

	void endVisitNull();

	boolean visitKey(String key);

	void endVisitKey(String key);

	void preVisit(Object value);

	void postVisit(Object value);
}

public interface JSONOutputVisitor extends JSONVisitor {
	Appendable getOut();
	
	void print(char ch);
	
	void print(String text);
}

public class JSONVisitorAdapter implements JSONVisitor {
	// ...
}

public class DefaultJSONOutputVisitor extends JSONVisitorAdapter implements JSONOutputVisitor {
}

public class JSONPrettyFormatOutputVisitor extends DefaultJSONOutputVisitor {
}

public interface JavaBeanHandler {
	void handle(Object javaBean, JSONVisitor visitor);
}

public class CGLibJavaBeanHandler implements JavaBeanHandler {
}

0 请登录后投票
   发表时间:2010-12-22   最后修改:2010-12-22
JSON类是主要入口,包括了toJSONString和parse系列方法。

JSON、JSONArray、JSONObject,这样的结构和其他的JSON库是类似的(如SimpleJSON、JSON-lib)。

其余就是Parser和Visitor的结构了。Visitor负责序列化,Parser负责反序列化。

注明一下,这里的Visitor是Visitor模式的变种,缺省Visitor模式的accept方法是在被访问对象中实现的,我这里的情况比较特殊,accept系列方法在Visitor中实现乐。
0 请登录后投票
   发表时间:2010-12-22   最后修改:2010-12-22
举例:
User user = new User();
List<User> userList = new ArrayList<User>();

String jsonString1 = JSON.toJSONStringEx(user);
String jsonString2 = JSON.toJSONStringEx(userList);

User user1 = JSON.parseObject(User.class, jsonString1 ); 
List<User> userList1 = JSON.parseArray(User.class, jsonString2 );

0 请登录后投票
   发表时间:2010-12-22  
wenshao 写道
谢谢校长进行codereview,指出了其中isDigit函数的问题,尝试多种办法测试之后,发现综合最快的是范围判断。linux kernel的isDigit算法,在Java中性能不稳定,只是在Windows XP 32bit JVM中-client参数时最快,其他测试环境都慢。

最终采用的实现如下,很简单的:
public final boolean isDigit(char ch) {
return ch >= '0' && ch <= '9';
}

linux kernel的isDigit算法如下:
private static final boolean[] digitBits = new boolean[256];
static {
for (char ch = '0'; ch <= '9'; ++ch) {
digitBits[ch] = true;
}
}
public final boolean isDigit(char ch) {
return digitBits[ch];
}
这是典型的空间换时间的思路,但在java中,这是性能不稳定的算法,估计是hotspot搞鬼了。

这次调整之后,性能又提升了几个百分点。


温少,身为阿里的大P,说话可要严谨奥,有些事情可以拍脑袋想,但是要讲出来,还是要思量,经过验证,总说“性能提高几个百分点”,什么情况,到底几个?测试的场景是啥子?牛可以吹,但是骨子里还是要严谨的啊
0 请登录后投票
   发表时间:2010-12-22   最后修改:2010-12-23
举例说明API:
public static class User {
	private String name;
	private int age;
	private BigDecimal salary;
	private Date birthdate; // 支持日期

	public Date getBirthdate() {
		return birthdate;
	}

	public void setBirthdate(Date birthdate) {
		this.birthdate = birthdate;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public BigDecimal getSalary() {
		return salary;
	}

	public void setSalary(BigDecimal salary) {
		this.salary = salary;
	}

}

public static class Group {
	private List<User> users = new ArrayList<User>();

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public List<User> getUsers() {
		return users;
	}

        // 支持泛性
	// 还支持另外一种写法 public void setUsers(List<? extends User> users) 
	public void setUsers(List<User> users) { 
		this.users = users;
	}
}

public void testComposite() throws Exception {
	Group group = new Group();
	group.setName("神棍");
	
	User user = new User();
	user.setName("校长");
	user.setAge(3);
	user.setSalary(new BigDecimal("123456789.0123"));
    user.setSalary(new BigDecimal("123456789.0123"));
	
	group.getUsers().add(user);
	
	String jsonString = JSON.toJSONStringEx(group);

	System.out.println(jsonString);

	JSON.parseObject(jsonString);
	Group group1 = JSON.parseObject(Group.class, jsonString);
	Assert.assertEquals(group.getName(), group1.getName());
	
	User user1 = group1.getUsers().get(0);
	Assert.assertEquals(user.getAge(), user1.getAge());
	Assert.assertEquals(user.getName(), user1.getName());
	Assert.assertEquals(user.getSalary(), user1.getSalary());
}
0 请登录后投票
   发表时间:2010-12-22  
基本可以收工了吧

性能已经解决了,扩展性已经解决了,功能还算完整的,日期、组合对象、泛型都支持了。。。

为了一个吹牛,连续两天加班到晚上11点多,没有加班工资的加班,可怜啊。。。
0 请登录后投票
   发表时间:2010-12-22  
superwwt 写道
sky3380 写道
wenshao 写道
谢谢校长进行codereview,指出了其中isDigit函数的问题,尝试多种办法测试之后,发现综合最快的是范围判断。linux kernel的isDigit算法,在Java中性能不稳定,只是在Windows XP 32bit JVM中-client参数时最快,其他测试环境都慢。

最终采用的实现如下,很简单的:
public final boolean isDigit(char ch) {
return ch >= '0' && ch <= '9';
}

linux kernel的isDigit算法如下:
private static final boolean[] digitBits = new boolean[256];
static {
for (char ch = '0'; ch <= '9'; ++ch) {
digitBits[ch] = true;
}
}
public final boolean isDigit(char ch) {
return digitBits[ch];
}
这是典型的空间换时间的思路,但在java中,这是性能不稳定的算法,估计是hotspot搞鬼了。

这次调整之后,性能又提升了几个百分点。


请教一下,为什么不能用Character.isDigit(c),也是因为性能吗?


为啥是256个呢?不就只要判断0-9就行了么?

会越界的,不过Java里的char值可不止256个

0 请登录后投票
   发表时间:2010-12-23  
我想, 各位, 开源是需要经过各种手续的。 我也很期待温少的小东东能拿出来给大家看看, 或者能用上。 我们会给大家更大一些的惊喜。
0 请登录后投票
   发表时间:2010-12-23   最后修改:2010-12-23
fengjia10 写道
wenshao 写道
谢谢校长进行codereview,指出了其中isDigit函数的问题,尝试多种办法测试之后,发现综合最快的是范围判断。linux kernel的isDigit算法,在Java中性能不稳定,只是在Windows XP 32bit JVM中-client参数时最快,其他测试环境都慢。

最终采用的实现如下,很简单的:
public final boolean isDigit(char ch) {
return ch >= '0' && ch <= '9';
}

linux kernel的isDigit算法如下:
private static final boolean[] digitBits = new boolean[256];
static {
for (char ch = '0'; ch <= '9'; ++ch) {
digitBits[ch] = true;
}
}
public final boolean isDigit(char ch) {
return digitBits[ch];
}
这是典型的空间换时间的思路,但在java中,这是性能不稳定的算法,估计是hotspot搞鬼了。

这次调整之后,性能又提升了几个百分点。


温少,身为阿里的大P,说话可要严谨奥,有些事情可以拍脑袋想,但是要讲出来,还是要思量,经过验证,总说“性能提高几个百分点”,什么情况,到底几个?测试的场景是啥子?牛可以吹,但是骨子里还是要严谨的啊


一个8K的文本,来自真是业务场景的数据,里面有很多数字,这个场景恰好是被Jackson针对性优化过的那种,isDigit函数性能的提升,使得比Jackson在这个场景下的差距又拉大的一点,大约3%的性能提升。

尻,明明标题说了是吹牛,你那么认真干嘛,吓唬我么!!!


0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics