<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Here comes the Sun &#187; 手艺</title>
	<atom:link href="http://sunng.info/blog/category/%e6%89%8b%e8%89%ba/feed/" rel="self" type="application/rss+xml" />
	<link>http://sunng.info/blog</link>
	<description>Homemade Clojure Geek</description>
	<lastBuildDate>Fri, 11 May 2012 02:24:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>多线程服务器</title>
		<link>http://sunng.info/blog/2012/04/%e5%a4%9a%e7%ba%bf%e7%a8%8b%e6%9c%8d%e5%8a%a1%e5%99%a8/</link>
		<comments>http://sunng.info/blog/2012/04/%e5%a4%9a%e7%ba%bf%e7%a8%8b%e6%9c%8d%e5%8a%a1%e5%99%a8/#comments</comments>
		<pubDate>Thu, 12 Apr 2012 15:52:15 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[NIO]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1219</guid>
		<description><![CDATA[写了挺长时间网络程序了，有些事到最近才弄明白，记录一下。 写一个高性能的服务器，传统的BIO方式基本上已经被淘汰了，很难获得理想的性能。所以现在都是以事件驱动的方式来写，在Linux上用epoll,Java平台上就是NIO。再向上，有一些包装的库，比如twisted比如libevent比如Java上的Netty。 Netty的server需要至少两组线程，BossPool和WorkerPool,。前者负责accept，后者负责r/w。通常的例子里，这就是仅有的两组线程。用户在框架之上的业务逻辑，写在handler里，以单线程的方式运行在worker线程上。 这样的方式在很多例子里很普遍。但是如果handler里的业务逻辑比较复杂，尤其是IO的等待过长(比如查询数据库)，就会由于在handler上阻塞的时间过长，导致服务器读写的效率下降。所以通常是不能在这样环境下的handler里写IO阻塞的代码。 解决这个问题，一种方式是多线程，一种是全异步化。后者最典型的例子就是nodejs，坦白说编程模型非常复杂，对开发者要求较高。一种相对简单的办法，就是以多线程的方式，增加CPU的利用效率，来平衡IO阻塞带来的影响。IO等待时间的比重越大，线程数就可以陪得越高。牺牲一些sy的CPU时间，换取更高的利用率。 但是随之而来了另一个问题，因为在handler中使用了多线程的模型。对顺序收到的包，交由不同的线程并行处理，就没有办法保证返回时的顺序。客户端就无法了解刚刚返回的包是对应哪个请求的。 这个情况也有两种办法处理。其一是在线程管理上做文章，采用一种折中的办法。对于每一个客户端连接来说，仍然是占用同一个线程来处理。这样首先任务不会占用worker线程，其次在整体上仍然提高了CPU的利用率。但是这样做的缺点是，在单一客户端看来，任务仍然是串行执行: 三个需要耗时500ms的请求同时顺序发出，第三个至少要在1500ms之后才能收到响应，客户端的latency比较高。 另一种，就是在应用协议层面做一个冗余字段，通常叫做serial id或者transaction id。客户端为每一个请求生成一个这样的id，并存储这个id对应的回调。服务器端不需要对包的顺序作任何关注，只需要把这个id原封不动地拷贝回去即可。这样，服务器就可以自由调度线程来处理请求。以上面的例子，在不繁忙的情况下，三个响应在500ms左右就都可以到达了。 这种方式对应用协议有特殊的要求，但是比较常见的协议都预留了这个字段，Diameter协议甚至留了两个这样的字段来便于代理的实现。 slacker 0.7.x基于aleph，由于aleph / lamina无法侵入协议层面，所以采用的都是顺序的客户端和服务器。这种方式编程非常简洁，协议设计简单，实现起来很快。但是作为RPC框架，一旦客户的函数阻塞较长，就会影响整体性能。0.8.0开始，通过新的协议和link库支持，slacker采用了transaction id的方式，服务器端默认使用并行处理，客户端不再依赖顺序指定响应和回调。尽管在一些CPU为局限的测试里性能有少许下降(与单线程相比，增加了调度的成本)，但是针对实际应用里IO等待较多的情况，新版本应该会表现出更好的综合性能。 以上这些，就是最近的心得，希望能解释清楚事件驱动服务器里的这些事情。]]></description>
			<content:encoded><![CDATA[<p>写了挺长时间网络程序了，有些事到最近才弄明白，记录一下。</p>
<p>写一个高性能的服务器，传统的BIO方式基本上已经被淘汰了，很难获得理想的性能。所以现在都是以事件驱动的方式来写，在Linux上用epoll,Java平台上就是NIO。再向上，有一些包装的库，比如twisted比如libevent比如Java上的Netty。</p>
<p>Netty的server需要至少两组线程，BossPool和WorkerPool,。前者负责accept，后者负责r/w。通常的例子里，这就是仅有的两组线程。用户在框架之上的业务逻辑，写在handler里，以单线程的方式运行在worker线程上。</p>
<p>这样的方式在很多例子里很普遍。但是如果handler里的业务逻辑比较复杂，尤其是IO的等待过长(比如查询数据库)，就会由于在handler上阻塞的时间过长，导致服务器读写的效率下降。所以通常是不能在这样环境下的handler里写IO阻塞的代码。</p>
<p>解决这个问题，一种方式是多线程，一种是全异步化。后者最典型的例子就是nodejs，坦白说编程模型非常复杂，对开发者要求较高。一种相对简单的办法，就是以多线程的方式，增加CPU的利用效率，来平衡IO阻塞带来的影响。IO等待时间的比重越大，线程数就可以陪得越高。牺牲一些sy的CPU时间，换取更高的利用率。</p>
<p>但是随之而来了另一个问题，因为在handler中使用了多线程的模型。对顺序收到的包，交由不同的线程并行处理，就没有办法保证返回时的顺序。客户端就无法了解刚刚返回的包是对应哪个请求的。</p>
<p>这个情况也有两种办法处理。其一是在线程管理上做文章，采用一种折中的办法。对于每一个客户端连接来说，仍然是占用同一个线程来处理。这样首先任务不会占用worker线程，其次在整体上仍然提高了CPU的利用率。但是这样做的缺点是，在单一客户端看来，任务仍然是串行执行: 三个需要耗时500ms的请求同时顺序发出，第三个至少要在1500ms之后才能收到响应，客户端的latency比较高。</p>
<p>另一种，就是在应用协议层面做一个冗余字段，通常叫做serial id或者transaction id。客户端为每一个请求生成一个这样的id，并存储这个id对应的回调。服务器端不需要对包的顺序作任何关注，只需要把这个id原封不动地拷贝回去即可。这样，服务器就可以自由调度线程来处理请求。以上面的例子，在不繁忙的情况下，三个响应在500ms左右就都可以到达了。</p>
<p>这种方式对应用协议有特殊的要求，但是比较常见的协议都预留了这个字段，Diameter协议甚至留了两个这样的字段来便于代理的实现。</p>
<p>slacker 0.7.x基于aleph，由于aleph / lamina无法侵入协议层面，所以采用的都是顺序的客户端和服务器。这种方式编程非常简洁，协议设计简单，实现起来很快。但是作为RPC框架，一旦客户的函数阻塞较长，就会影响整体性能。0.8.0开始，通过新的协议和link库支持，slacker采用了transaction id的方式，服务器端默认使用并行处理，客户端不再依赖顺序指定响应和回调。尽管在一些CPU为局限的测试里性能有少许下降(与单线程相比，增加了调度的成本)，但是针对实际应用里IO等待较多的情况，新版本应该会表现出更好的综合性能。</p>
<p>以上这些，就是最近的心得，希望能解释清楚事件驱动服务器里的这些事情。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2012/04/%e5%a4%9a%e7%ba%bf%e7%a8%8b%e6%9c%8d%e5%8a%a1%e5%99%a8/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Slacker performance enhanced</title>
		<link>http://sunng.info/blog/2012/04/slacker-performance-enhanced/</link>
		<comments>http://sunng.info/blog/2012/04/slacker-performance-enhanced/#comments</comments>
		<pubDate>Mon, 02 Apr 2012 07:04:21 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[netty]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[slacker]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1216</guid>
		<description><![CDATA[In the slacker framework, performance issue becomes more and more critical as the basic features are almost completed. As mentioned in cnclojure meetup, I will focus on the performance enhancement in next release. Now I have worked out a testable &#8230; <a href="http://sunng.info/blog/2012/04/slacker-performance-enhanced/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In the slacker framework, performance issue becomes more and more critical as the basic features are almost completed. As mentioned in cnclojure meetup, I will focus on the performance enhancement in next release. </p>
<p>Now I have worked out a testable version. The new slacker core has been moved to a new NIO library, <a href="https://github.com/sunng87/link" target="_blank">link</a>. Compared with aleph, link is a thin wrapper of Netty. It takes some nice features from aleph (gloss codec dsl, elegant API), and drops the heavy abstraction, lamina. The new slacker client runs on a real nonblocking connection. Connection pooling is no longer needed.</p>
<p>I have some performance benchmark to visualize the improvement. The test was made on my laptop (Intel(R) Core(TM)2 Duo CPU     T5870  @ 2.00GHz). It ran 400,000 calls with 40 threads on a local slacker server.</p>
<p>slacker 0.7.0 (clojure 1.2, aleph 0.2.0): <strong>614005.059259msecs</strong><br />
slacker 0.7.1-SNAPSHOT (clojure 1.3, aleph 0.2.1-beta2): <strong>409110.909142msecs</strong><br />
slacker 0.8.0-SNAPSHOT (clojure 1.3, link 0.2.0-SNAPSHOT): <strong>42468.401522msecs</strong></p>
<p><img src="http://i.imgur.com/gMtdo.jpg" alt="tps chart" /></p>
<p>Check out the new slacker on the <a href="https://github.com/sunng87/slacker/tree/0.8-dev" target="_blank">0.8-dev</a> branch. </p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2012/04/slacker-performance-enhanced/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Slacker slides on cnclojure meetup</title>
		<link>http://sunng.info/blog/2012/03/slacker-slides-on-cnclojure-meetup/</link>
		<comments>http://sunng.info/blog/2012/03/slacker-slides-on-cnclojure-meetup/#comments</comments>
		<pubDate>Tue, 06 Mar 2012 13:50:22 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[slacker]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1192</guid>
		<description><![CDATA[从北京回来两天了，稍微有点累，还没来得及总结一下，先把slides上传分享一下： http://www.box.com/s/k0alcj1p115jq40bdkik 解压之后 lein deps &#038;&#038; lein run 一下即可。 这是一个借助impress.js制作的幻灯片。之所以让它跑在webbit里，是因为我简单hack了impress.js让你可以通过websocket远程控制幻灯片播放。这样，就可以通过手机上的firefox浏览器（目前android上仅有firefox支持websocket）控制播放，把手机变成一款遥控器。]]></description>
			<content:encoded><![CDATA[<p>从北京回来两天了，稍微有点累，还没来得及总结一下，先把slides上传分享一下： <a href="http://www.box.com/s/k0alcj1p115jq40bdkik" target="_blank">http://www.box.com/s/k0alcj1p115jq40bdkik</a></p>
<p>解压之后 lein deps &#038;&#038; lein run 一下即可。</p>
<p>这是一个借助impress.js制作的幻灯片。之所以让它跑在webbit里，是因为我简单hack了impress.js让你可以通过websocket远程控制幻灯片播放。这样，就可以通过手机上的firefox浏览器（目前android上仅有firefox支持websocket）控制播放，把手机变成一款遥控器。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2012/03/slacker-slides-on-cnclojure-meetup/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>dosync+: dosync with event listener</title>
		<link>http://sunng.info/blog/2012/02/dosync-dosync-with-event-listener/</link>
		<comments>http://sunng.info/blog/2012/02/dosync-dosync-with-event-listener/#comments</comments>
		<pubDate>Fri, 24 Feb 2012 14:25:06 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[clojure]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1188</guid>
		<description><![CDATA[Discussed in clojure-cn mailing list, we come up with an extensible dosync block with event listener: on-start, on-retry and on-committed. With these extension points, you can bind STM monitor to a transaction. And I believe there will more advanced use &#8230; <a href="http://sunng.info/blog/2012/02/dosync-dosync-with-event-listener/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Discussed in clojure-cn mailing list, we come up with an extensible dosync block with event listener: on-start, on-retry and on-committed.</p>
<p><script src="https://gist.github.com/1898383.js?file=dosync-plus.clj"></script></p>
<p>With these extension points, you can bind STM monitor to a transaction. And I believe there will more advanced use cases on this.</p>
<p><script src="https://gist.github.com/1898383.js?file=main.clj"></script></p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2012/02/dosync-dosync-with-event-listener/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用Enlive作为模板引擎</title>
		<link>http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8enlive%e4%bd%9c%e4%b8%ba%e6%a8%a1%e6%9d%bf%e5%bc%95%e6%93%8e/</link>
		<comments>http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8enlive%e4%bd%9c%e4%b8%ba%e6%a8%a1%e6%9d%bf%e5%bc%95%e6%93%8e/#comments</comments>
		<pubDate>Thu, 29 Dec 2011 13:13:19 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1125</guid>
		<description><![CDATA[在所有的clojure web开发例子里，对模板的介绍都很少。很多的简单例子都是以hiccup作为页面生成的手段。hiccup是个clojure的html DSL，例子里用这样的DSL生成页面确实很酷，可是他是real world吗，当然不是。 好在clojure世界里早就有了enlive，它不仅是一个通过css selector解析html的库，本身也可以作为模板引擎应用在web开发中。我不知道这种通过css selector的方式是否是enlive首创，不过他实在是非常新颖独特，而且平滑了页面设计和程序的集成。 例如这样一个模板 index.html： &#60;div id=&#34;cc&#34;&#62;Sample Text&#60;/div&#62; 在clojure程序中，使用enlive的deftemplate &#40;deftemplate index &#34;index.html&#34; &#160; &#91;ctx&#93; &#160; &#91;:div#cc&#93; &#40;content &#40;:data ctx&#41;&#41;&#41; 在控制器里，可以很MVC地渲染页面 &#40;index &#123;:data &#34;rendered text&#34;&#125;&#41; 除了content用于渲染文本，还有html-content可以渲染含html标签的内容，以及set-attr用来修改页面元素的属性。 和传统的模板引擎相比，最大的不同是enlive里没有嵌入模板的直观的控制流，没有循环和条件判断，但是并非不可实现。 循环输出一组list 页面 list.html &#60;ul id=&#34;the-list&#34;&#62; &#60;li class=&#34;list-item&#34;&#62;&#60;/li&#62; &#60;/ul&#62; 定义一个enlive的snippet &#40;defsnippet &#8230; <a href="http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8enlive%e4%bd%9c%e4%b8%ba%e6%a8%a1%e6%9d%bf%e5%bc%95%e6%93%8e/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>在所有的clojure web开发例子里，对模板的介绍都很少。很多的简单例子都是以hiccup作为页面生成的手段。hiccup是个clojure的html DSL，例子里用这样的DSL生成页面确实很酷，可是他是real world吗，当然不是。</p>
<p>好在clojure世界里早就有了enlive，它不仅是一个通过css selector解析html的库，本身也可以作为模板引擎应用在web开发中。我不知道这种通过css selector的方式是否是enlive首创，不过他实在是非常新颖独特，而且平滑了页面设计和程序的集成。</p>
<p>例如这样一个模板 index.html：</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;cc&quot;</span>&gt;</span>Sample Text<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span></div></div>
<p>在clojure程序中，使用enlive的deftemplate</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>deftemplate index <span style="color: #ff0000;">&quot;index.html&quot;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>ctx<span style="color: #66cc66;">&#93;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>:<span style="color: #555;">div</span>#cc<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>content <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">data</span> ctx<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>在控制器里，可以很MVC地渲染页面</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>index <span style="color: #66cc66;">&#123;</span>:<span style="color: #555;">data</span> <span style="color: #ff0000;">&quot;rendered text&quot;</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>除了content用于渲染文本，还有html-content可以渲染含html标签的内容，以及set-attr用来修改页面元素的属性。</p>
<p>和传统的模板引擎相比，最大的不同是enlive里没有嵌入模板的直观的控制流，没有循环和条件判断，但是并非不可实现。</p>
<p>循环输出一组list</p>
<p>页面 list.html</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/ul.html"><span style="color: #000000; font-weight: bold;">ul</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;the-list&quot;</span>&gt;</span><br />
<span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/li.html"><span style="color: #000000; font-weight: bold;">li</span></a> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;list-item&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/li.html"><span style="color: #000000; font-weight: bold;">li</span></a>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/ul.html"><span style="color: #000000; font-weight: bold;">ul</span></a>&gt;</span></div></div>
<p>定义一个enlive的snippet</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>defsnippet item<span style="color: #66cc66;">-</span>model <span style="color: #ff0000;">&quot;page.html&quot;</span> <span style="color: #66cc66;">&#91;</span>:<span style="color: #66cc66;">.</span>list<span style="color: #66cc66;">-</span>item<span style="color: #66cc66;">&#93;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>ctx<span style="color: #66cc66;">&#93;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>:<span style="color: #66cc66;">.</span>list<span style="color: #66cc66;">-</span>item<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>content <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">data</span> ctx<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>在页面模板里</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>deftemplate list<span style="color: #66cc66;">-</span>page <span style="color: #ff0000;">&quot;list.html&quot;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>ctx<span style="color: #66cc66;">&#93;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>:<span style="color: #555;">ul</span>#the<span style="color: #66cc66;">-</span>list<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>content <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">map</span> item<span style="color: #66cc66;">-</span>model <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">some</span><span style="color: #66cc66;">-</span>list ctx<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>这样在页面里列表项会被循环输出，而在页面设计时这里可以放任意个li，并且直接交给后台作为模板。</p>
<p>条件判断</p>
<p>页面，设计时显示所有的内容 msg.html</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/span.html"><span style="color: #000000; font-weight: bold;">span</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;msg&quot;</span>&gt;</span>只在一定条件下显示<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/span.html"><span style="color: #000000; font-weight: bold;">span</span></a>&gt;</span></div></div>
<p>在模板中通过clojure的if进行判断</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>deftemplate msg <span style="color: #ff0000;">&quot;msg.html&quot;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>ctx<span style="color: #66cc66;">&#93;</span><br />
&nbsp; <span style="color: #66cc66;">&#91;</span>:<span style="color: #555;">span</span>#msg<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">show</span> ctx<span style="color: #66cc66;">&#41;</span> identity <span style="color: #66cc66;">&#40;</span>html<span style="color: #66cc66;">-</span>content <span style="color: #ff0000;">&quot;&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>解决了这两个问题，基本上用enlive作为模板引擎就没有障碍了。不过enlive也有一点小问题，其一可能是性能的问题，方便的selector显然要比传统的模板语言消耗更多的CPU。另外，在开发过程里，页面文件在服务器启动后不能热加载，修改页面必须重启ring才能看到。也许有时间的话，可以给它加一个reload选项。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8enlive%e4%bd%9c%e4%b8%ba%e6%a8%a1%e6%9d%bf%e5%bc%95%e6%93%8e/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用Clojure Thread Macro的心得</title>
		<link>http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8clojure-thread-macro%e7%9a%84%e5%bf%83%e5%be%97/</link>
		<comments>http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8clojure-thread-macro%e7%9a%84%e5%bf%83%e5%be%97/#comments</comments>
		<pubDate>Fri, 16 Dec 2011 14:44:00 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[macro]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1096</guid>
		<description><![CDATA[Thread Macro是clojure里一个很强大的宏，他帮助你简化嵌套函数的调用，比如 &#40;str &#40;inc &#40;count &#91;:a :b&#93;&#41;&#41;&#41; 就可以利用thread macro简写成 &#40;-&#62; &#91;:a :b&#93; count inc str&#41; -&#62;&#62;和-&#62;类似，区别在于-&#62;&#62;把值作为函数的最后一个参数传入。 简单的功能介绍完了，接下来就遇到问题了。我需要功能，能够接受一个或多个函数，然后把这些函数组成一个pipeline。这时很自然想到-&#62;是一个好帮手。也许只需要一个类似这样的form就可以了： #(apply -&#62; % [funcs])。结果失败了，因为-&#62;是个宏，所以根本不能用apply。于是想到有apply-macro吗？有，或者说曾经有过。在contrib中曾经有一个apply-macro，不过被强烈不推荐使用。到这里，这条路堵死了，惟一的办法就是把-&#62;放到API之外，放到用户代码里去。 放到用户代码里，你需要写一个详细的说明文档并且告诉用户他必须这么做。然而在clojure世界里有一个更好的办法就是再写一个宏把-&#62;包装起来。这么做看似多此一举，其实是保持了API的一致性。通过宏，我们可以把自己的API延伸到用户代码中去。或者说，通过一个类似DSL的宏，给一些并不优雅的API一个缓冲，也为API日后的演化留下空间。 这里还要扯开一句关于宏的开发。clojure中所谓code is data，主要就是体现在宏里。原本在多数其他语言里，宏是不能求值的。但是在clojure里，由于code is data的缘故，宏是可以求值的。所有的输入数据都是list，你可以做first/reverse这样的操作。但是有一点要注意的是，宏中求得的值和代码里的值是不一样的。例如{:a inc}这样一个字面量，在宏里是可以通过:a做求值的，然后这里得到的并非一个函数（function），而是一个符号（symbol）。再者，调试宏的时候你可能会被这样的结果困惑： &#40;defmacro a &#91;f&#93; &#40;println &#40;:a f&#41;&#41;&#41; &#40;a &#123;:a 1&#125;&#41; ; ==&#62; prints &#8230; <a href="http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8clojure-thread-macro%e7%9a%84%e5%bf%83%e5%be%97/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Thread Macro是clojure里一个很强大的宏，他帮助你简化嵌套函数的调用，比如</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">str</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">inc</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">count</span> <span style="color: #66cc66;">&#91;</span>:<span style="color: #555;">a</span> :<span style="color: #555;">b</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>就可以利用thread macro简写成</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #66cc66;">&#91;</span>:<span style="color: #555;">a</span> :<span style="color: #555;">b</span><span style="color: #66cc66;">&#93;</span> <span style="color: #b1b100;">count</span> <span style="color: #b1b100;">inc</span> <span style="color: #b1b100;">str</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>-&gt;&gt;和-&gt;类似，区别在于-&gt;&gt;把值作为函数的最后一个参数传入。</p>
<p>简单的功能介绍完了，接下来就遇到问题了。我需要功能，能够接受一个或多个函数，然后把这些函数组成一个pipeline。这时很自然想到-&gt;是一个好帮手。也许只需要一个类似这样的form就可以了： #(apply -&gt; % [funcs])。结果失败了，因为-&gt;是个宏，所以根本不能用apply。于是想到有apply-macro吗？有，或者说曾经有过。在contrib中曾经有一个apply-macro，不过被强烈不推荐使用。到这里，这条路堵死了，惟一的办法就是把-&gt;放到API之外，放到用户代码里去。</p>
<p>放到用户代码里，你需要写一个详细的说明文档并且告诉用户他必须这么做。然而在clojure世界里有一个更好的办法就是再写一个宏把-&gt;包装起来。这么做看似多此一举，其实是保持了API的一致性。通过宏，我们可以把自己的API延伸到用户代码中去。或者说，通过一个类似DSL的宏，给一些并不优雅的API一个缓冲，也为API日后的演化留下空间。</p>
<p>这里还要扯开一句关于宏的开发。clojure中所谓code is data，主要就是体现在宏里。原本在多数其他语言里，宏是不能求值的。但是在clojure里，由于code is data的缘故，宏是可以求值的。所有的输入数据都是list，你可以做first/reverse这样的操作。但是有一点要注意的是，宏中求得的值和代码里的值是不一样的。例如{:a inc}这样一个字面量，在宏里是可以通过:a做求值的，然后这里得到的并非一个函数（function），而是一个符号（symbol）。再者，调试宏的时候你可能会被这样的结果困惑：</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">defmacro</span> a <span style="color: #66cc66;">&#91;</span>f<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>println <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">a</span> f<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>a <span style="color: #66cc66;">&#123;</span>:<span style="color: #555;">a</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">; ==&gt; prints 1</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> b <span style="color: #66cc66;">&#123;</span>:<span style="color: #555;">a</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>a b<span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">; ==&gt; prints nil</span></div></div>
<p>字面量可以，同值的变量就不行了。原因还是那句，宏里不能求值。</p>
<p>继续谈-&gt;。这个宏其实远没有你想象的那么驯服。遇到复杂一点的情况：</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> m <span style="color: #66cc66;">&#123;</span>:<span style="color: #555;">a</span> <span style="color: #b1b100;">inc</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">str</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>这个写法对吗？str是个函数，(get m :a)返回的是inc也是个函数，貌似正确。运行之后却报错get的参数数量错误。所以千万不要忘了-&gt;是个宏，(get m :a)这里是不会求值到inc的，直接作为一个list被宏吞下去。在宏里只能通过符号的组合变化来生成代码，那么一不小心，就没有inc什么事了。</p>
<p>于是，你可能想到这里需要一个确切的函数，就好比这样：</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> m <span style="color: #66cc66;">&#123;</span>:<span style="color: #555;">a</span> <span style="color: #b1b100;">inc</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #66cc66;">&#91;</span>x<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>也许这样就好多了，我们放了一个匿名函数，并不要求宏去求值，因为这个匿名函数会被宏生成到新的代码里。里面的get也会在运行时求值。看似没什么问题，可是一运行还是没有期待的结果，居然返回了一个匿名函数！而对这个匿名函数求值得到的也是一个错误的结果！简直有点无厘头了。</p>
<p>呵呵，不故弄玄虚了。我们用macroexpand看看发生了什么。</p>
<p>这是用匿名函数包装以前</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>macroexpand<span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span> '<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>get <span style="color: #cc66cc;">2</span> m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>-&gt;居然只是简单地把2放到了get这个form里面！</p>
<p>再看看用匿名函数包装后的结果</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>macroexpand<span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span> '<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #66cc66;">&#91;</span>x<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#91;</span>x<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>和刚才一样，2被放到了第一个form的第一个参数位置！得到的是一个非法的form。</p>
<p>那么既然-&gt;只是简单地把第一个参数放到后面form的首个参数的位置，那么这个宏正确的使用方法其实是</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> m <span style="color: #66cc66;">&#123;</span>:<span style="color: #555;">a</span> <span style="color: #b1b100;">inc</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #66cc66;">&#91;</span>x<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>再加一层括号！</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>macroexpand<span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span> '<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">-&gt;</span> <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #66cc66;">&#91;</span>x<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">fn</span> <span style="color: #66cc66;">&#91;</span>x<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>get m :<span style="color: #555;">a</span><span style="color: #66cc66;">&#41;</span> x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>可见，-&gt;虽然是个功能强大的宏，但宏终归只是宏，和函数的区别是明显的。在使用的时候，不能完全按照函数的习惯。</p>
<p>如果你想了解实际的代码，可以参考slacker 0.3.0里的这个interceptor框架：<br />
<a href="https://github.com/sunng87/slacker/blob/master/src/slacker/interceptor.clj" target="_blank">https://github.com/sunng87/slacker/blob/master/src/slacker/interceptor.clj</a><br />
上面提到的难处，多半也都是在开发这个框架时亲身经历的。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/12/%e4%bd%bf%e7%94%a8clojure-thread-macro%e7%9a%84%e5%bf%83%e5%be%97/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Clojure RPC, prototyping and early thoughts</title>
		<link>http://sunng.info/blog/2011/11/clojure-rpc-prototyping-and-early-thoughts/</link>
		<comments>http://sunng.info/blog/2011/11/clojure-rpc-prototyping-and-early-thoughts/#comments</comments>
		<pubDate>Sun, 27 Nov 2011 08:47:34 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[opensource]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1070</guid>
		<description><![CDATA[Last week, I prototyped an RPC framework, slacker, by clojure and for clojure. What I did ? Suppose you have a sets of clojure functions to expose. Define them under a namespace: &#40;ns slapi&#41; &#40;defn timestamp &#91;&#93; &#160; &#40;System/currentTimeMillis&#41;&#41; ;; &#8230; <a href="http://sunng.info/blog/2011/11/clojure-rpc-prototyping-and-early-thoughts/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Last week, I prototyped an RPC framework, <a href="https://github.com/sunng87/slacker" target="_blank">slacker</a>, by clojure and for clojure. </p>
<h3>What I did ?</h3>
<p>Suppose you have a sets of clojure functions to expose. Define them under a namespace:</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">ns</span> slapi<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">defn</span> timestamp <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#93;</span><br />
&nbsp; <span style="color: #66cc66;">&#40;</span>System<span style="color: #66cc66;">/</span>currentTimeMillis<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #808080; font-style: italic;">;; ...more functions</span></div></div>
<p>Expose the namespace with slacker server, on port 2104:</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>use 'slacker<span style="color: #66cc66;">.</span>server<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>start<span style="color: #66cc66;">-</span>slacker<span style="color: #66cc66;">-</span>server <span style="color: #66cc66;">&#40;</span>the<span style="color: #66cc66;">-</span><span style="color: #b1b100;">ns</span> 'slapi<span style="color: #66cc66;">&#41;</span> <span style="color: #cc66cc;">2104</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>On the client side, we use the `defremote` macro to create a facade for `timestamp` function. This API will keep the client code consistent with local mode.</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>use 'slacker<span style="color: #66cc66;">.</span>client<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">def</span> sc <span style="color: #66cc66;">&#40;</span>slackerc <span style="color: #ff0000;">&quot;localhost&quot;</span> <span style="color: #cc66cc;">2104</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>defremote sc timestamp<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>timestamp<span style="color: #66cc66;">&#41;</span></div></div>
<p>Internally, slacker uses <a href="https://github.com/ztellman/aleph" target="_blank">aleph</a> for transport and <a href="https://github.com/revelytix/carbonite" target="_blank">carbonite</a> for serialization. I forked carbonite and made it compatible with clojure 1.2 because the aleph mainline is still running on 1.2. </p>
<h3>Going further</h3>
<h4>High-Order Functions</h4>
<p>In clojure, functions are treated as first class value. Within memory, you can pass function as parameter to another function. However, this is not supported by serialization framework. So is it possible to add support for that in future?</p>
<h4>Lazy sequence as parameter</h4>
<p>This is another interesting feature in clojure function call. You can pass a lazy-sequence to clojure function. In RPC, it requires parameters to be evaluated on the server side.</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">defn</span> get<span style="color: #66cc66;">-</span><span style="color: #b1b100;">first</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&amp;</span> args<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">first</span> args<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">apply</span> get<span style="color: #66cc66;">-</span><span style="color: #b1b100;">first</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">range</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>Example copied from <a href="http://stackoverflow.com/q/8205446/371141" target="_blank">StackOverflow</a></p>
<h4>Coordinated states between several remote servers</h4>
<p>With RPC, we can update states on several servers. So do we need something like distributed dosync:</p>
<div class="codecolorer-container clojure twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="clojure codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>defremote a1 update<span style="color: #66cc66;">-</span>a1<span style="color: #66cc66;">-</span>state<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>defremote a2 update<span style="color: #66cc66;">-</span>a2<span style="color: #66cc66;">-</span>state<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#40;</span>dosync<span style="color: #66cc66;">-</span>distributed<br />
&nbsp; <span style="color: #66cc66;">&#40;</span>update<span style="color: #66cc66;">-</span>a1<span style="color: #66cc66;">-</span>state some<span style="color: #66cc66;">-</span>value<span style="color: #66cc66;">&#41;</span><br />
&nbsp; <span style="color: #66cc66;">&#40;</span>update<span style="color: #66cc66;">-</span>a2<span style="color: #66cc66;">-</span>state some<span style="color: #66cc66;">-</span>value<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>I&#8217;m not sure if this is a valid scenario in real world but I think it&#8217;s an interesting topic.(distributed STM?)</p>
<h3>Conclusion</h3>
<p>RPC is the first step to distributed clojure world. I will keep you updated with my prototype. </p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/11/clojure-rpc-prototyping-and-early-thoughts/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Spark in common lisp</title>
		<link>http://sunng.info/blog/2011/11/spark-in-common-lisp/</link>
		<comments>http://sunng.info/blog/2011/11/spark-in-common-lisp/#comments</comments>
		<pubDate>Sat, 19 Nov 2011 06:26:09 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[lisp]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1068</guid>
		<description><![CDATA[还是关于spark的，一石激起千层浪，每个人心中都有一个spark。其实spark脚本刚出来的时候问题很多，但是就是因为产生了共鸣，众人拾柴pull request多。像redis的作者antirez也忍不住自己用c写了一个aspark。 说完了别人的，那么来看看我的：clspark，common-lisp的spark。原本是打算用clojure写，但是想到jvm的启动速度，把这个机会留给我的第一个common lisp程序吧。 其实很简单。 common lisp的核心库里没有split，所以这里从cl-cookbook拷贝了一个split的实现，坦白说我还看不太懂这个loop的写法。loop是common lisp中最尴尬的form，因为他的形式太多。这点在clojure中是不存在的。比较一下就能发现，在语言层面，clojure是相对现代得多的lisp方言。]]></description>
			<content:encoded><![CDATA[<p>还是关于spark的，一石激起千层浪，每个人心中都有一个spark。其实spark脚本刚出来的时候问题很多，但是就是因为产生了共鸣，众人拾柴pull request多。像redis的作者antirez也忍不住自己用c写了一个<a href="https://github.com/antirez/aspark" target="_blank">aspark</a>。</p>
<p>说完了别人的，那么来看看我的：clspark，common-lisp的spark。原本是打算用clojure写，但是想到jvm的启动速度，把这个机会留给我的第一个common lisp程序吧。</p>
<p><img src="http://i.imgur.com/oD7m4.png" alt="" /></p>
<p>其实很简单。<br />
<script src="https://gist.github.com/1375401.js"> </script></p>
<p>common lisp的核心库里没有split，所以这里从cl-cookbook拷贝了一个split的实现，坦白说我还看不太懂这个loop的写法。loop是common lisp中最尴尬的form，因为他的形式太多。这点在clojure中是不存在的。比较一下就能发现，在语言层面，clojure是相对现代得多的lisp方言。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/11/spark-in-common-lisp/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Grails的核心依赖必须保证项目中版本一致！</title>
		<link>http://sunng.info/blog/2011/10/grails%e7%9a%84%e6%a0%b8%e5%bf%83%e4%be%9d%e8%b5%96%e5%bf%85%e9%a1%bb%e4%bf%9d%e8%af%81%e9%a1%b9%e7%9b%ae%e4%b8%ad%e7%89%88%e6%9c%ac%e4%b8%80%e8%87%b4%ef%bc%81/</link>
		<comments>http://sunng.info/blog/2011/10/grails%e7%9a%84%e6%a0%b8%e5%bf%83%e4%be%9d%e8%b5%96%e5%bf%85%e9%a1%bb%e4%bf%9d%e8%af%81%e9%a1%b9%e7%9b%ae%e4%b8%ad%e7%89%88%e6%9c%ac%e4%b8%80%e8%87%b4%ef%bc%81/#comments</comments>
		<pubDate>Sat, 15 Oct 2011 14:51:43 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[maven]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1037</guid>
		<description><![CDATA[好久没写语录式大标题了，实在是今天玩Grails受害很深很深。 Grails因为本身是通过ivy来管理依赖的，虽然后续的版本和maven的集成不断加深，但是本身还是通过ivy来解析pom.xml。也就是说最后的活还是ivy干的。如果你的项目比较大，选择了通过maven来管理项目，而你的依赖中又牵扯了很多其他的依赖，那么你危险了。 :: UNRESOLVED DEPENDENCIES :: :: log4j#log4j;1.2.16: configuration not found in log4j#log4j;1.2.16: &#8216;master&#8217;. It was required from &#8230;;1.7.0 runtime 对maven用户这是一条多么发指的报错！（比如这个） 它的原因其实是你的dependency中有!=1.2.16版本你的log4j，比如1.2.12，即使你在pom里将它添加到了exclusion中也没有用，必须要保持版本的一致！至于你用什么办法让他们保持一致，还是干脆放弃用maven管理你的grails项目：It&#8217;s up to you. 同样的问题还出现在其他核心依赖上，例如commons-pool。]]></description>
			<content:encoded><![CDATA[<p>好久没写语录式大标题了，实在是今天玩Grails受害很深很深。</p>
<p>Grails因为本身是通过ivy来管理依赖的，虽然后续的版本和maven的集成不断加深，但是本身还是通过ivy来解析pom.xml。也就是说最后的活还是ivy干的。如果你的项目比较大，选择了通过maven来管理项目，而你的依赖中又牵扯了很多其他的依赖，那么你危险了。</p>
<blockquote><p>:: UNRESOLVED DEPENDENCIES ::</p>
<p>:: log4j#log4j;1.2.16: configuration not found in log4j#log4j;1.2.16: &#8216;master&#8217;. It was required from &#8230;;1.7.0 runtime</p></blockquote>
<p>对maven用户这是一条多么发指的报错！（比如<a href="http://forum.springsource.org/showthread.php?104033-Can-not-load-a-log4J-library" target="_blank">这个</a>）</p>
<p>它的原因其实是你的dependency中有!=1.2.16版本你的log4j，比如1.2.12，即使你在pom里将它添加到了exclusion中也没有用，必须要保持版本的一致！至于你用什么办法让他们保持一致，还是干脆放弃用maven管理你的grails项目：It&#8217;s up to you.</p>
<p>同样的问题还出现在其他核心依赖上，例如commons-pool。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/10/grails%e7%9a%84%e6%a0%b8%e5%bf%83%e4%be%9d%e8%b5%96%e5%bf%85%e9%a1%bb%e4%bf%9d%e8%af%81%e9%a1%b9%e7%9b%ae%e4%b8%ad%e7%89%88%e6%9c%ac%e4%b8%80%e8%87%b4%ef%bc%81/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The distribution of intelligence</title>
		<link>http://sunng.info/blog/2011/10/the-distribution-of-intelligence/</link>
		<comments>http://sunng.info/blog/2011/10/the-distribution-of-intelligence/#comments</comments>
		<pubDate>Mon, 10 Oct 2011 06:03:25 +0000</pubDate>
		<dc:creator>sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[heatcanvas]]></category>
		<category><![CDATA[visualization]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=1027</guid>
		<description><![CDATA[This could be a big title for the content. I just work out a heat map based on the data of users who enrolled online courses offered by Stanford. (Click to enlarge) I think you already have your ideas about &#8230; <a href="http://sunng.info/blog/2011/10/the-distribution-of-intelligence/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This could be a big title for the content.</p>
<p>I just work out a heat map based on <a href="http://maps.google.com/maps/ms?ie=UTF&#038;msa=0&#038;msid=203716810039202316490.0004aeb1b1a01b1d3b9af" target="_blank">the data</a> of users who enrolled online courses offered by Stanford.</p>
<p><a href="http://imgur.com/rWUkH"><img src="http://i.imgur.com/rWUkH.png" width="500" alt="" title="Hosted by imgur.com" /></a><br />
(Click to enlarge)</p>
<p>I think you already have your ideas about this map. New England, California and Central Europe has higher density than any other area of the world. Also you can find some light in South America, East Coast Australia, India and China. I think this could be an overview of how intelligence distributed around the globe.</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2011/10/the-distribution-of-intelligence/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

