<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blog.darkthread.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Darkthread</title><link>http://blog.darkthread.net/blogs/</link><description>黑暗執行緒</description><dc:language>en-US</dc:language><generator>CommunityServer 2007.1 (Debug Build: 20917.1142)</generator><item><title>CODE-Convert Text to PDF in C#</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/02/09/text-to-pdf.aspx</link><pubDate>Tue, 09 Feb 2010 05:12:49 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:6000</guid><dc:creator>Jeffrey</dc:creator><slash:comments>2</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;透過程式直接將Text內容轉換成PDF的程式範例，寫來給其他組同事做為系統整合模組開發參考，順便PO文備忘。&lt;/p&gt; &lt;p&gt;要在.NET轉PDF，當然少不了大家都說讚的&lt;a href="http://itextsharp.sourceforge.net/"&gt;iTextSharp&lt;/a&gt;，程式很簡單，我還順手加了一個遇到&amp;quot;\f&amp;quot; (0x0C) Form Feed符號就強制換新頁的功能。&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class="BlogCodeBlock"&gt; &lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="asp"&gt;&amp;lt;%@ Page Language=&amp;quot;C#&amp;quot; %&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="asp"&gt;&amp;lt;%@ Import Namespace=&amp;quot;iTextSharp.text&amp;quot; %&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="asp"&gt;&amp;lt;%@ Import Namespace=&amp;quot;iTextSharp.text.pdf&amp;quot; %&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="asp"&gt;&amp;lt;%@ Import Namespace=&amp;quot;System.IO&amp;quot; %&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; btnConvert_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;&lt;pre&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="rem"&gt;//REF: http://www.codeproject.com/KB/graphics/iTextSharpTutorial.aspx&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;        Document doc = &lt;span class="kwrd"&gt;new&lt;/span&gt; Document(PageSize.A4.Rotate());&lt;/pre&gt;&lt;pre class="alt"&gt;        &lt;/pre&gt;&lt;pre&gt;        &lt;span class="kwrd"&gt;using&lt;/span&gt; (MemoryStream ms = &lt;span class="kwrd"&gt;new&lt;/span&gt; MemoryStream())&lt;/pre&gt;&lt;pre class="alt"&gt;        {&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;            {&lt;/pre&gt;&lt;pre class="alt"&gt;                PdfWriter.GetInstance(doc, ms);&lt;/pre&gt;&lt;pre&gt;                doc.Open();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="rem"&gt;//中文字型問題REF &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="rem"&gt;//http://renjin.blogspot.com/2009/01/using-chinese-fonts-in-itextsharp.html&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt; fontPath = &lt;/pre&gt;&lt;pre&gt;                    Environment.GetFolderPath(&lt;/pre&gt;&lt;pre class="alt"&gt;                    Environment.SpecialFolder.System) +&lt;/pre&gt;&lt;pre&gt;                    &lt;span class="str"&gt;@&amp;quot;\..\Fonts\kaiu.ttf&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;                BaseFont bfChinese = BaseFont.CreateFont(&lt;/pre&gt;&lt;pre&gt;                    fontPath,&lt;/pre&gt;&lt;pre class="alt"&gt;                    BaseFont.IDENTITY_H, &lt;span class="rem"&gt;//橫式中文&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;                    BaseFont.NOT_EMBEDDED&lt;/pre&gt;&lt;pre class="alt"&gt;                );&lt;/pre&gt;&lt;pre&gt;                Font fontChinese = &lt;span class="kwrd"&gt;new&lt;/span&gt; Font(bfChinese, 8f, Font.NORMAL);&lt;/pre&gt;&lt;pre class="alt"&gt;                &lt;/pre&gt;&lt;pre&gt;                StringReader sr = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringReader(txtInput.Text);&lt;/pre&gt;&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt; line = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;                &lt;span class="kwrd"&gt;while&lt;/span&gt; ((line = sr.ReadLine()) != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre class="alt"&gt;                {&lt;/pre&gt;&lt;pre&gt;                    &lt;span class="kwrd"&gt;string&lt;/span&gt;[] p = line.Split(&lt;span class="str"&gt;&amp;#39;\f&amp;#39;&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;                    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; s &lt;span class="kwrd"&gt;in&lt;/span&gt; p)&lt;/pre&gt;&lt;pre&gt;                    {&lt;/pre&gt;&lt;pre class="alt"&gt;                        doc.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Paragraph(s, fontChinese));&lt;/pre&gt;&lt;pre&gt;                        &lt;span class="kwrd"&gt;if&lt;/span&gt; (p.Length &amp;gt; 1) &lt;span class="rem"&gt;//表示有換頁符號&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;                            doc.NewPage();&lt;/pre&gt;&lt;pre&gt;                    }&lt;/pre&gt;&lt;pre class="alt"&gt;                }&lt;/pre&gt;&lt;pre&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (DocumentException de)&lt;/pre&gt;&lt;pre&gt;            {&lt;/pre&gt;&lt;pre class="alt"&gt;                Response.Write(de.Message);&lt;/pre&gt;&lt;pre&gt;                Response.End();&lt;/pre&gt;&lt;pre class="alt"&gt;            }&lt;/pre&gt;&lt;pre&gt;            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (IOException ioe)&lt;/pre&gt;&lt;pre class="alt"&gt;            {&lt;/pre&gt;&lt;pre&gt;                Response.Write(ioe.Message);&lt;/pre&gt;&lt;pre class="alt"&gt;                Response.End();&lt;/pre&gt;&lt;pre&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;            doc.Close();&lt;/pre&gt;&lt;pre&gt;            &lt;span class="rem"&gt;//Output PDF&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;            Response.Clear();&lt;/pre&gt;&lt;pre&gt;            Response.ContentType = &lt;span class="str"&gt;&amp;quot;application/octet-stream&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;            Response.AddHeader(&lt;span class="str"&gt;&amp;quot;content-disposition&amp;quot;&lt;/span&gt;, &lt;/pre&gt;&lt;pre&gt;                &lt;span class="str"&gt;&amp;quot;attachment;filename=output.pdf&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;            Response.BinaryWrite(ms.ToArray());&lt;/pre&gt;&lt;pre&gt;            Response.End();&lt;/pre&gt;&lt;pre class="alt"&gt;        }&lt;/pre&gt;&lt;pre&gt;                    &lt;/pre&gt;&lt;pre class="alt"&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Text to PDF demo&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;form&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;form1&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:TextBox&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;txtInput&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;600px&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;TextMode&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;MultiLine&amp;quot;&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;            &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;800px&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;asp:TextBox&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:Button&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;btnConvert&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;onclick&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;btnConvert_Click&amp;quot;&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;            &lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Convert to PDF&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;form&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=6000" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/.NET/default.aspx">.NET</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/CODE/default.aspx">CODE</category></item><item><title>CODE-SetTimeout/ClearTimeout in C#</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/02/07/settimeout-func-for-c.aspx</link><pubDate>Sat, 06 Feb 2010 23:44:41 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5991</guid><dc:creator>Jeffrey</dc:creator><slash:comments>3</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt;  &lt;p&gt;正在從事&lt;strong&gt;&lt;font color="#ff8000"&gt;以休閒為目的Coding活動&lt;/font&gt;&lt;/strong&gt;時，忽然有個衝動想在C#中也用一下Javascript裡常用的setTimeout/clearTimeout。&lt;/p&gt;  &lt;p&gt;setTimeout說穿了就是透過另一條Thread執行程式產生非同步效果，用.NET實作是小菜一碟，而我想挑戰的是如何用最簡潔的方法實作出來。&lt;/p&gt;  &lt;p&gt;剛好這陣子陸續玩過&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/12/27/action-delegate.aspx"&gt;Action&amp;lt;T&amp;gt; and Func&amp;lt;T&amp;gt;&lt;/a&gt;、&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/12/26/closure-in-c.aspx"&gt;Closure in C#&lt;/a&gt;，加上&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/22/multicore-3.aspx"&gt;研究Parallel.For()&lt;/a&gt;時被迫反覆寫了十來次，現在已經練就信手就可掰出一段Thread配Lambda範例的境界。這個題目拿來作為隨堂考試再適合也不過了。&lt;/p&gt;  &lt;p&gt;在Action加Lambda加Closure的加持之下，只要不到30行程式就可以在C#中使用SetTimeout/ClearTimeout囉~~~ C#真是簡潔有力的好語言呀!&lt;/p&gt;  &lt;p&gt;先看程式碼，後面再提一下重點:&lt;/p&gt;  &lt;div class="BlogCodeBlock"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Forms;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Threading;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; WindowsFormsApplication1&lt;/pre&gt;

    &lt;pre class="alt"&gt;{&lt;/pre&gt;

    &lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Form1 : Form&lt;/pre&gt;

    &lt;pre class="alt"&gt;    {&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; Form1()&lt;/pre&gt;

    &lt;pre class="alt"&gt;        {&lt;/pre&gt;

    &lt;pre&gt;            InitializeComponent();&lt;/pre&gt;

    &lt;pre class="alt"&gt;        }&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Form1_Load(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;

    &lt;pre&gt;        {&lt;/pre&gt;

    &lt;pre class="alt"&gt;            &lt;span class="rem"&gt;//No UI thread issue, use SetTimeout(cb, delay)&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;            SetTimeout(() =&amp;gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;            {&lt;/pre&gt;

    &lt;pre&gt;                MessageBox.Show(&lt;span class="str"&gt;&amp;quot;First&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre class="alt"&gt;            }, 2000);&lt;/pre&gt;

    &lt;pre&gt;            SetTimeout(() =&amp;gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;            {&lt;/pre&gt;

    &lt;pre&gt;                listBox1.Items.Add(&lt;span class="str"&gt;&amp;quot;Second&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre class="alt"&gt;            }, 4000, &lt;span class="kwrd"&gt;this&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre&gt;            Guid hnd = SetTimeout(() =&amp;gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;            {&lt;/pre&gt;

    &lt;pre&gt;                listBox1.Items.Add(&lt;span class="str"&gt;&amp;quot;Third&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre class="alt"&gt;            }, 6000, &lt;span class="kwrd"&gt;this&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre&gt;            SetTimeout(() =&amp;gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;            {&lt;/pre&gt;

    &lt;pre&gt;                listBox1.Items.Add(&lt;span class="str"&gt;&amp;quot;Forth&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre class="alt"&gt;            }, 8000, &lt;span class="kwrd"&gt;this&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre&gt;            ClearTimeout(hnd);&lt;/pre&gt;

    &lt;pre class="alt"&gt;        }&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="preproc"&gt;#region&lt;/span&gt; SetTimeout/ClearTimeout Simulation&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="rem"&gt;//Dictionary for running setTimeout&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;static&lt;/span&gt; Dictionary&amp;lt;Guid, Thread&amp;gt; _setTimeoutHandles =&lt;/pre&gt;

    &lt;pre&gt;            &lt;span class="kwrd"&gt;new&lt;/span&gt; Dictionary&amp;lt;Guid, Thread&amp;gt;();&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="rem"&gt;//SetTimeout for no UI Thread issue&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="kwrd"&gt;static&lt;/span&gt; Guid SetTimeout(Action cb, &lt;span class="kwrd"&gt;int&lt;/span&gt; delay)&lt;/pre&gt;

    &lt;pre class="alt"&gt;        {&lt;/pre&gt;

    &lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; SetTimeout(cb, delay, &lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre class="alt"&gt;        }&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="rem"&gt;//Javascript-style SetTimeout function&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="rem"&gt;//remember to set uiForm argument when there cb is trying&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="rem"&gt;//to change UI controls in window form&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="rem"&gt;//it will return a GUID as handle for cancelling&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="kwrd"&gt;static&lt;/span&gt; Guid SetTimeout(Action cb, &lt;span class="kwrd"&gt;int&lt;/span&gt; delay, Form uiForm)&lt;/pre&gt;

    &lt;pre class="alt"&gt;        {&lt;/pre&gt;

    &lt;pre&gt;            Guid g = Guid.NewGuid();&lt;/pre&gt;

    &lt;pre class="alt"&gt;            Thread t = &lt;span class="kwrd"&gt;new&lt;/span&gt; Thread(() =&amp;gt;&lt;/pre&gt;

    &lt;pre&gt;            {&lt;/pre&gt;

    &lt;pre class="alt"&gt;                Thread.Sleep(delay);&lt;/pre&gt;

    &lt;pre&gt;                _setTimeoutHandles.Remove(g);&lt;/pre&gt;

    &lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (uiForm != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;

    &lt;pre&gt;                    &lt;span class="rem"&gt;//use Invoke() to avoid threading issue&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    &lt;span class="rem"&gt;//Ref: http://tinyurl.com/yjckzhz&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;                    uiForm.Invoke(cb);&lt;/pre&gt;

    &lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;                    cb();&lt;/pre&gt;

    &lt;pre class="alt"&gt;            });&lt;/pre&gt;

    &lt;pre&gt;            _setTimeoutHandles.Add(g, t);&lt;/pre&gt;

    &lt;pre class="alt"&gt;            t.Start();&lt;/pre&gt;

    &lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; g;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        }&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="rem"&gt;//Javascript-style ClearTimeout&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ClearTimeout(Guid g)&lt;/pre&gt;

    &lt;pre&gt;        {&lt;/pre&gt;

    &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!_setTimeoutHandles.ContainsKey(g))&lt;/pre&gt;

    &lt;pre&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;

    &lt;pre class="alt"&gt;            _setTimeoutHandles[g].Abort();&lt;/pre&gt;

    &lt;pre&gt;            _setTimeoutHandles.Remove(g);&lt;/pre&gt;

    &lt;pre class="alt"&gt;        }&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    }&lt;/pre&gt;

    &lt;pre&gt;}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;重點補充:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;SetTimeout的原理是呼叫端傳入Action參數及延遲微秒(ms)數後，立即新增一條Thread執行&amp;quot;&lt;strong&gt;&lt;font color="#ff8000"&gt;先Thread.Delay()指定時間長度再呼叫所傳入的Action&lt;/font&gt;&lt;/strong&gt;&amp;quot;，並將控制權交回呼叫端，邏輯十分單純。 &lt;/li&gt;

  &lt;li&gt;由於SetTimeout傳入要延遲執行的Action程式實際上會由另一條Thread執行，若在該邏輯中變動Window Form上的元素，就會違背&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2007/09/30/tips-about-ui-thread-limitation.aspx"&gt;不可透過非UI Thread去更動UI元素&lt;/a&gt;的規則。因此，我們再多增加一個Form參數，當有需要時，透過Form.Invoke()間接執行才可避開UI Thread限制。 &lt;/li&gt;

  &lt;li&gt;要能ClearTimeout，就必須保留Thread變數，必要時將其Abort()掉。
    &lt;br /&gt;我用了一個Diction&amp;lt;Guid, Thread&amp;gt;來保存Thread，SetTimeout時Dictionary.Add()並傳回一個GUID，ClearTimeout時可憑該GUID去中止尚未執行的排程。&lt;/li&gt;

  &lt;li&gt;理論上，ClearTimeout只能中止&amp;quot;仍在等待執行的工作&amp;quot;，因此Thread.Delay一結束時，就立刻Dictionary.Remove(GUID) (這裡剛好展現了&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/12/26/closure-in-c.aspx"&gt;Closure&lt;/a&gt;的美妙之處)，不再允許ClearTimeout，否則程式都跑了一半還胡亂Thread.Abort()會出人命的。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;寫完再回頭看，短短30行Code還真扯到不少進階的東西(Action, Closure, Threading)，看懂的人C# Coding能力應該都在中階以上了吧!(純個人意見，勿戰) 對這一段還不熟的人可以參考以前PO過的幾篇文章當起頭，但我想還需要參考官方文件、網路範例配合實地動手寫過才容易完全理解。&lt;/p&gt;

&lt;p&gt;&lt;font color="#ff8000"&gt;【延伸閱讀】&lt;/font&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2008/06/13/lambda-expression.aspx"&gt;Lambda演算式&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/02/5831.aspx"&gt;如何透過Lambda精簡Threading程式&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/12/27/action-delegate.aspx"&gt;Action&amp;lt;T&amp;gt; and Func&amp;lt;T&amp;gt;&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2007/09/30/tips-about-ui-thread-limitation.aspx"&gt;UI Thread限制&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/12/26/closure-in-c.aspx"&gt;Closure in C#&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5991" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/.NET/default.aspx">.NET</category></item><item><title>MEMO-用Javascript RegExp將&lt;x&gt;置換成&lt;span class="x"&gt;</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/02/06/js-regexp-replace-sample.aspx</link><pubDate>Sat, 06 Feb 2010 06:27:00 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5989</guid><dc:creator>Jeffrey</dc:creator><slash:comments>1</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;每次都記不太住Javascript RegExp要怎麼做複雜的Replace(例如: 將比對相符的字串內容變成新置換文字的一部分，標題說的&amp;quot;將&amp;lt;x&amp;gt;換成&amp;lt;span class=&amp;#39;x&amp;#39;&amp;gt;&amp;quot;就是典型案例)，特別記錄一下供未來年老回憶之用。&lt;/p&gt; &lt;p&gt;我遇到的實際需求是想將Sharepoint查詢結果中的高亮註記&amp;lt;c1&amp;gt;, &amp;lt;c2&amp;gt;分別轉成&amp;lt;span class=&amp;#39;hl1&amp;quot;&amp;gt;, &amp;lt;span class=&amp;quot;hl2&amp;quot;&amp;gt;。&lt;/p&gt; &lt;p&gt;例如:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font color="#00ff00"&gt;、&amp;lt;c2&amp;gt;晶圓&amp;lt;/c2&amp;gt;雙雄... 有利&amp;lt;c1&amp;gt;台灣&amp;lt;/c1&amp;gt;出口業加速復甦，而&amp;lt;c1&amp;gt;台灣&amp;lt;/c1&amp;gt;程式魔人族群亦在持續擴大中，符合投顧的預期...&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;要轉成&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font color="#00ff00"&gt;、&amp;lt;span class=&amp;#39;hl2&amp;#39;&amp;gt;晶圓&amp;lt;/span&amp;gt;雙雄... 有利&amp;lt;span class=&amp;#39;hl1&amp;#39;&amp;gt;台灣&amp;lt;/span&amp;gt;出口業加速復甦，而&amp;lt;span class=&amp;#39;hl1&amp;#39;&amp;gt;台灣&amp;lt;/span&amp;gt;程式魔人族群亦在持續擴大中，符合投顧的預期...&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;程式說穿了不值一文錢，但也好歹讓我試了十來分鐘，不寫下來恐怕下回又得要再花十分鐘，所以有了這篇備忘文。&lt;/p&gt; &lt;div class="BlogCodeBlock"&gt; &lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; s = &lt;span class="str"&gt;&amp;quot;、\u003cc2\u003e晶圓\u003c/c2\u003e雙雄... 有利\u003cc1\u003e台灣\u003c/c1\u003e出口業加速復甦，而\u003cc1\u003e台灣\u003c/c1\u003e程式魔人族群亦在持續擴大中，符合投顧的預期...&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; regex = /[&amp;lt;]c(\d)&amp;gt;/g;&lt;/pre&gt;&lt;pre class="alt"&gt;s = s.replace(regex, &lt;span class="str"&gt;&amp;quot;&amp;lt;span class=&amp;#39;hl$1&amp;#39;&amp;gt;&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;regex = /[&amp;lt;]\/c\d&amp;gt;/g;&lt;/pre&gt;&lt;pre class="alt"&gt;s = s.replace(regex, &lt;span class="str"&gt;&amp;quot;&amp;lt;/span&amp;gt;&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;【後記】這是我目前唯一一個在&lt;a href="http://playpcesor.blogspot.com/2010/01/keep-focused-25-pomodoro.html"&gt;一顆蕃茄&lt;/a&gt;(25min)內搞定的工作項目--&lt;b&gt;&lt;font color="#ff8000"&gt;研究如何用Javascript置換SPS搜尋結果的高亮CSS&lt;/font&gt;&lt;/b&gt;，然後拿剩下的10分鐘跟偷偷佔用的休息時間寫了這篇文章 XD&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5989" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Javascript/default.aspx">Javascript</category></item><item><title>在.NET 3.5中使用Parallel.For()</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/02/05/tpl-for-3-5.aspx</link><pubDate>Fri, 05 Feb 2010 09:25:31 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5984</guid><dc:creator>Jeffrey</dc:creator><slash:comments>0</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;網友&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/22/multicore-3.aspx#5980"&gt;KENCHAO&lt;/a&gt;問到&amp;quot;&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/22/multicore-3.aspx"&gt;好威的Parallel.For&lt;/a&gt;可以用在.NET 3.5上&amp;quot;嗎?&lt;/p&gt; &lt;p&gt;微軟在Task Parallel Library &lt;a href="http://msdn.microsoft.com/zh-tw/magazine/cc163340.aspx"&gt;CTP版本時代&lt;/a&gt;，曾提供過相容於.NET 3.5的Microsoft Parallel Extensions for .NET Framework 3.5。但找了一下，官方似乎已不再提供該版本的下載... 但是別氣餒，依據MS Parallel Programming RD小組在2009年11月的PO文，有一個來自個&lt;a href="http://msdn.microsoft.com/en-us/devlabs/default.aspx"&gt;DevLabs&lt;/a&gt;的替代解決方案--&lt;a href="http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx"&gt;Reactive Extensions to .NET&lt;/a&gt; (Rx)，其中有個System.Threading.dll可向前相容Parallel Extensions for .NET Framework 3.5(但不提供技術支援)，靠著它，我們就可讓Parallel.For在.NET 3.5中也大顯神威~~~&lt;/p&gt; &lt;p&gt;從&lt;a href="http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx"&gt;Rx首頁&lt;/a&gt;下載【Rx for .NET Framework 3.5 SP1】，安裝後你可以在C:\Program Files\Microsoft Reactive Extensions\Redist\DesktopV2 找到System.Threading.dll。&lt;/p&gt; &lt;p&gt;用VS2008開啟一個.NET 3.5專案，新增參考指向剛才提到的System.Threading.dll，在程式開端加個using System.Threading.Tasks宣告，接著在程式碼中就可以大大方方地使用Parallel.For囉!&lt;/p&gt; &lt;p&gt;&lt;img class="PopBoxImageSmall" src="http://blog.darkthread.net/photos/darkthread/images/5983/500x375.aspx" alt="" /&gt;&lt;/p&gt; &lt;p&gt;不過，要注意幾點:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;在.NET 3.5使用TPL所能展現的效能會遜於.NET 4.0，理由是.NET 4.0在ThreadPool及一些效能調校上還做了額外增強。  &lt;li&gt;不提供官方支援。  &lt;li&gt;透過.NET 3.5使用TPL時，無法享用VS2010的Parallel Task/Parallel Stack/Concurrency Visualizer等平行運算專屬新工具。  &lt;li&gt;OperationCanceledException的使用與.NET 4.0的版本有些差異。&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;雖然有以上限制，但能在.NET 3.5裡用Parallel.For()簡化原本囉嗦的多執行緒寫法，畢竟還是件爽快的事，值得一試!&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5984" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Performance/default.aspx">Performance</category></item><item><title>解決Virtual PC網路分享存取暴慢的問題</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/30/vpc-net-slow.aspx</link><pubDate>Sat, 30 Jan 2010 00:36:09 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5973</guid><dc:creator>Jeffrey</dc:creator><slash:comments>5</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt;  &lt;p&gt;在Windows 7使用Virtual PC VM時發現一個嚴重問題，當透過網路分享方式存取VM分享資料夾時，傳輸速度慢到嚇人!&lt;/p&gt;  &lt;p&gt;例如: 我的Windows 7上有台Virtual PC VM(IP = 192.168.1.15)，當從Windows 7的C:\Softeware Copy檔案到\ \192.168.1.15\Downloads 時，速度暴慢，始終維持在16KB/s以下...&lt;/p&gt;  &lt;p&gt;&lt;img src="http://blog.darkthread.net/photos/darkthread/images/5971/original.aspx" alt="" /&gt;&lt;/p&gt;  &lt;p&gt;Windows 7與Virtual PC分明共用一張100M Ehternet網卡，卻只能用到128k，會不會太扯了一點? 簡直比扯鈴還扯呀~~~&lt;/p&gt;  &lt;p&gt;查詢到MS KB-&lt;a href="http://support.microsoft.com/?scid=kb%3Ben-us%3B888750"&gt;Slow performance when you try to access resources on your Virtual Server 2005 host computer from a guest virtual machine&lt;/a&gt;，裡面提到VM所模擬的DEC Intel 21140A網卡晶片不支援&lt;a href="http://en.wikipedia.org/wiki/Large_segment_offload"&gt;TCP Segmentation Offloading&lt;/a&gt;(這個火星術語翻譯成地球語就是: 把拆封包的工作交給網卡，減少CPU的負擔)，當主機啟用此功能時會造成網路速度變慢並衍生斷線等問題。&lt;/p&gt;  &lt;p&gt;KB建議的解決方式有三種:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;另外新增一張虛擬網卡(Microsoft Loopback Adapter)，VM改用虛擬網卡Routing上網。(我覺得這有點為了喝牛奶養牛) &lt;/li&gt;    &lt;li&gt;修改Registry，停用TCP Task Offloading。(此舉可能會增加CPU負擔，但我的CPU使用率很少超過5%，應該算是&amp;quot;九千牛一毛&amp;quot;吧! )&lt;/li&gt;    &lt;li&gt;不想全機停用TCP Task Offloading的話，可以只停用特定網卡的Offloading。(我只有一張網卡，所以用2也沒差)&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;最後我決定採用方法2，增加HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DisableTaskOffload後重新開機，再試一次搬檔，40MB/s!!! 對嘛，這才像話!&lt;/p&gt;  &lt;p&gt;&lt;img src="http://blog.darkthread.net/photos/darkthread/images/5972/original.aspx" alt="" /&gt;&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5973" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Trouble-Shooting/default.aspx">Trouble-Shooting</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Windows+7/default.aspx">Windows 7</category></item><item><title>Sharepoint Web Service NullReferenceException Error</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/29/sps-ws-nullref-error.aspx</link><pubDate>Fri, 29 Jan 2010 05:44:16 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5969</guid><dc:creator>Jeffrey</dc:creator><slash:comments>0</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;最近在整合Sharepoint的&lt;a href="http://msdn.microsoft.com/en-us/library/bb625970.aspx"&gt;Search.asmx&lt;/a&gt;做客製化，一路上波折不斷。&lt;/p&gt; &lt;p&gt;很幸運地，找到一個好用的Open Source查詢工具--&lt;a href="http://sharepointsearchserv.codeplex.com/"&gt;Sharepoint Search Sevice Tool&lt;/a&gt;，可以提供Scope、欄位資訊，用勾選就可以自動組出Query XML，按鈕後馬上看結果。複雜的Sharepoint Search瞬間被簡化，讓我這個新手在最短的時間可以進入狀況，真是勝造七級浮屠的聖品! (面對全然陌生的技術議題，當你手上有一個可以RUN的Sample，那種安全感無可言喻啊!)&lt;/p&gt; &lt;p&gt;不過，我並沒有因為獲得神奇道具就從此過著幸福快樂的日子。&lt;/p&gt; &lt;p&gt;我要處理的MOSS是由多台Server組成的Web Farm，測試發現同樣要連Search.asmx，某幾台Server OK，有幾台卻怎麼敲帳號密碼都不會過。仔細比對發現，有記憶連線帳號密碼的主機不必問帳號密碼就可以連上；遇上未記憶密碼的Server，怎麼輸入都會得到HTTP 401 UnauthorizedAccess Exception。&lt;/p&gt; &lt;p&gt;追了一下，發現問題出在原程式中未將Domain Name傳成NetworkCredential的第三個參數，修改後就可解決。(參考: &lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/28/networkcredential-for-domain-account.aspx"&gt;NOTES-NetworkCredential Constructor for Domain Account&lt;/a&gt;)&lt;/p&gt; &lt;p&gt;殺掉小魔王後，遇到另一個更機車的問題。例如: 我的Web Farm FQDN是sps2007.darkthread.net，其中有五台機器，192.168.100.1 - 192.168.100.5。結果連到192.168.100.1/192.168.100.2 Search.asmx可以正常查詢，連至3, 4, 5三台則在呼叫Search.asmx GetPortalSearchInfo()時出現NullReferenceException。&lt;/p&gt; &lt;p&gt;爬文半天也毫無頭緒，後來心一橫決定鋸箭! 由於呼叫GetPortalSearchInfo是用來取得Scope清單，而另一個Method GetSearchMetadata也可以取得Scope清單，在文件上更是建議用它取代GetPortalSerachInfo。我把GetPortalSearchInfo的程式碼刪除，將Scope擷取邏輯交給GetSearchMetadata，暫時就閃開了這個問題。&lt;/p&gt; &lt;p&gt;只可惜高興不到兩分鐘，這番鋸箭雖然可以讓我連上3,4,5號機列出Scope，但只要一Query，就會彈出System.ArgumentNullException!! 能正確執行的還是只有1,2號機。&lt;/p&gt; &lt;p&gt;到此，我已耗去兩天時間(其間還試著用Reflector查看GetPortalSearchInfo想找出端倪、也設法試跑過Managed Object Model、當然也爬了無數的文)，最後，看到有人提及用FQDN失敗、用Machine Name成功的&lt;a href="http://www.windows-tech.info/6/180c59c93c476e19.php"&gt;案例&lt;/a&gt;，給了我一線生機。&lt;/p&gt; &lt;p&gt;偵辦方向由程式API規格轉到與SPS設定上，於是便問了一下熟悉架構的同事，原來Sharepoint 2007是有玄機的，有個&lt;a href="http://technet.microsoft.com/zh-tw/library/cc261814.aspx"&gt;備用存取對應&lt;/a&gt;決定了內部URL與公用URL的對應，看到以下設定畫面的那一刻...&lt;/p&gt; &lt;p&gt;&lt;img src="http://blog.darkthread.net/photos/darkthread/images/5968/original.aspx" alt="" /&gt;&lt;/p&gt; &lt;p&gt;一切盡在不言中~~~&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5969" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Sharepoint/default.aspx">Sharepoint</category></item><item><title>CODE-Save ADO.NET DataTable As CSV</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/28/save-datatable-as-csv.aspx</link><pubDate>Thu, 28 Jan 2010 07:02:31 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5964</guid><dc:creator>Jeffrey</dc:creator><slash:comments>1</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;之前寫過&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/10/30/csv-to-datatable.aspx"&gt;將CSV檔案內容轉換成ADO.NET DataTable物件&lt;/a&gt;，今天的需求剛好反過來，要將DataTable的內容匯出成CSV，邏輯上簡單許多，但還是PO文一篇，下回需要時比較好找。&lt;/p&gt; &lt;div class="BlogCodeBlock"&gt; &lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Quoted(&lt;span class="kwrd"&gt;string&lt;/span&gt; v) {&lt;/pre&gt;&lt;pre&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;\&amp;quot;&amp;quot;&lt;/span&gt; + v.Replace(&lt;span class="str"&gt;@&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;@&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;) + &lt;span class="str"&gt;&amp;quot;\&amp;quot;&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;}&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SaveDataTableAsCSV(DataTable t, &lt;span class="kwrd"&gt;string&lt;/span&gt; csvPath)&lt;/pre&gt;&lt;pre&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;    StringBuilder sb = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();&lt;/pre&gt;&lt;pre&gt;    List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; l = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;();&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (DataColumn c &lt;span class="kwrd"&gt;in&lt;/span&gt; t.Columns)&lt;/pre&gt;&lt;pre&gt;        l.Add(Quoted(c.ColumnName));&lt;/pre&gt;&lt;pre class="alt"&gt;    sb.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Join(&lt;span class="str"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;, l.ToArray()));&lt;/pre&gt;&lt;pre&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (DataRow r &lt;span class="kwrd"&gt;in&lt;/span&gt; t.Rows)&lt;/pre&gt;&lt;pre class="alt"&gt;    {&lt;/pre&gt;&lt;pre&gt;        l.Clear();&lt;/pre&gt;&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; t.Columns.Count; i++)&lt;/pre&gt;&lt;pre&gt;            l.Add(Quoted(r[i].ToString()));&lt;/pre&gt;&lt;pre class="alt"&gt;        sb.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Join(&lt;span class="str"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;, l.ToArray()));&lt;/pre&gt;&lt;pre&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;    File.WriteAllText(csvPath, sb.ToString(), Encoding.UTF8);&lt;/pre&gt;&lt;pre&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;註: &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;File.WriteAllText時要加註Encoding.UTF8以&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/28/write-utf8-file-with-bom.aspx"&gt;確定輸出檔案會包含BOM檔頭&lt;/a&gt;，Excel才能正確開啟。&lt;/li&gt;
&lt;li&gt;測試發現，欄位內容值即使包含換行符號，也能被Excel正確解析，讓我驚喜了一下。&lt;/li&gt;&lt;/ol&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5964" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/CODE/default.aspx">CODE</category></item><item><title>NOTES-產生具有BOM的UTF8編碼檔案</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/28/write-utf8-file-with-bom.aspx</link><pubDate>Thu, 28 Jan 2010 06:50:32 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5963</guid><dc:creator>Jeffrey</dc:creator><slash:comments>0</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;上回有討論過&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/09/06/csv-encoding-again.aspx"&gt;Excel開啟CSV時的中文編碼問題&lt;/a&gt;，今天發現關於.NET處理&lt;a href="http://msdn.microsoft.com/en-us/library/system.text.utf8encoding.getpreamble.aspx"&gt;BOM&lt;/a&gt;的幾個特性，再補充三則筆記:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;雖然預設UTF8Encoding的&lt;a href="http://msdn.microsoft.com/en-us/library/s064f8w2.aspx"&gt;encoderShouldEmitUTF8Identifier&lt;/a&gt;參數預設為true，但GetBytes()的結果不會包含BOM  &lt;li&gt;File.WriteAllText與StreamWriter在沒有指定Encoding.UTF8時，會產出UTF-8編碼但沒有BOM的檔案  &lt;li&gt;以下的範例中，只有F2.csv、F4.csv可以正確被Excel開啟，原因請見&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/09/06/csv-encoding-again.aspx"&gt;上回文章&lt;/a&gt;。&lt;/li&gt;&lt;/ul&gt; &lt;div class="BlogCodeBlock"&gt; &lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; s = &lt;span class="str"&gt;&amp;quot;牛,牪,犇&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;File.WriteAllText(&lt;span class="str"&gt;&amp;quot;B:\\F1.csv&amp;quot;&lt;/span&gt;, s);&lt;/pre&gt;&lt;pre class="alt"&gt;File.WriteAllText(&lt;span class="str"&gt;&amp;quot;B:\\F2.csv&amp;quot;&lt;/span&gt;, s, Encoding.UTF8);&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; (StreamWriter sw = &lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;new&lt;/span&gt; StreamWriter(&lt;span class="str"&gt;&amp;quot;B:\\F3.csv&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;false&lt;/span&gt;))&lt;/pre&gt;&lt;pre&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;    sw.WriteLine(s);&lt;/pre&gt;&lt;pre&gt;    sw.Close();&lt;/pre&gt;&lt;pre class="alt"&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; (StreamWriter sw =&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;new&lt;/span&gt; StreamWriter(&lt;span class="str"&gt;&amp;quot;B:\\F4.csv&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;false&lt;/span&gt;, &lt;/pre&gt;&lt;pre&gt;        Encoding.UTF8))&lt;/pre&gt;&lt;pre class="alt"&gt;{&lt;/pre&gt;&lt;pre&gt;    sw.WriteLine(s);&lt;/pre&gt;&lt;pre class="alt"&gt;    sw.Close();&lt;/pre&gt;&lt;pre&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5963" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/_2D4E8765E87DBC78_/default.aspx">中文編碼</category></item><item><title>NOTES-NetworkCredential Constructor for Domain Account</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/28/networkcredential-for-domain-account.aspx</link><pubDate>Thu, 28 Jan 2010 04:37:49 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5960</guid><dc:creator>Jeffrey</dc:creator><slash:comments>0</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;這問題之前曾遇過幾次，但處理得有些含糊，這回特別做了測試釐清。&lt;/p&gt; &lt;p&gt;&lt;font color="#ff8000"&gt;【疑問】&lt;/font&gt;要用NetworkCredential設定存取身份時，網域帳號可否寫成&amp;quot;domainName\userName&amp;quot;，例如:&lt;font color="#00ff00"&gt; new NetworkCredential(&amp;quot;domainName\\userName&amp;quot;, &amp;quot;password&amp;quot;)&lt;/font&gt; ?&lt;/p&gt; &lt;p&gt;不知為什麼，我一直記得這樣寫是可行的(也許因為Windows的登入視窗，可以選擇domainName\userName或將domainName寫到第三個欄位吧?)，今天實地做了測試，答案是: (分別測試了Windows 2000/Windows 2003、在Web本機存取自己的Web、本網域/信任網域...)&lt;/p&gt; &lt;p&gt;不行!!! 請乖乖寫成&lt;font color="#00ff00"&gt;new NetworkCredential(&amp;quot;userName&amp;quot;, &amp;quot;password&amp;quot;, &amp;quot;domainName&amp;quot;)&lt;/font&gt;&lt;/p&gt; &lt;p&gt;不過，為求方便，我們應該要允許使用者輸入&amp;quot;domainName\userName&amp;quot;，然後在程式裡用以下方法快速拆解:&lt;br /&gt;&lt;font color="#00ff00"&gt;if (userName.Contains(&amp;quot;\\&amp;quot;)) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string[] p = userName.Split(&amp;#39;\\&amp;#39;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cred = new NetworkCredential(p[1], password, p[0]);&lt;br /&gt;}&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color="#ff8000"&gt;【網友經驗】&lt;/font&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://blog.csdn.net/smile2me27/archive/2005/01/14/253321.aspx"&gt;System.Net.NetworkCredential的第一个参数&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5960" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/.NET/default.aspx">.NET</category></item><item><title>【茶包射手日記】失落的change事件</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/26/change-event-not-fired.aspx</link><pubDate>Tue, 26 Jan 2010 06:19:44 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5955</guid><dc:creator>Jeffrey</dc:creator><slash:comments>3</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;有個網頁在某欄位的change事件掛了一段邏輯，依輸入內容連動其他欄位值。使用者抱怨上個月第一次使用完全正常，這個月再用時，在該欄位中輸入資料，其他欄位卻未跟著連動...&lt;/p&gt; &lt;p&gt;我用自己的Client連到同一網頁，跟User輸入同樣的值，一切正常。移駕到使用者座位，使用&amp;quot;肇事&amp;quot;機器實地操作，連動功能也完全正常! 莫非，這程式會認主人，只要遇到拎杯親自操作就不敢造次?&lt;/p&gt; &lt;p&gt;世界上有很多無法解釋的玄妙事件，但本案例並不包含在內。依茶包射手實戰手冊第748頁的記載，此種靈異現象&lt;font color="#ff8000"&gt;通常是User與Developer在操作上有細微差異才造成不同結果，最好的處理方式是請User依&amp;quot;平日習慣&amp;quot;操作一次，實地進行觀察。&lt;/font&gt;終於發現端倪了! 原來，使用者這個月Key單時輸入該欄位的資料跟上月雷同，於是好心的IE亮出了&amp;quot;自動完成&amp;quot;提示(如下圖示意)，能少打字當然要省，User使Click一下自動帶入；而我在測試時，為了確保change被觸發，潛意識驅使之下是一個字母一個字母手動輸入。重點來了--IE的自動完成有一項特性，&lt;font color="#ff8000"&gt;它 不 會 觸 發 change 事 件&lt;/font&gt; !&lt;/p&gt; &lt;p&gt;&lt;img src="http://blog.darkthread.net/photos/darkthread/images/5954/original.aspx" alt="" /&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;參考文獻: &lt;a href="http://msdn.microsoft.com/en-us/library/ms533032%28VS.85%29.aspx"&gt;Using AutoComplete in HTML Forms&lt;/a&gt;&lt;br /&gt;&lt;em&gt;To determine when a user updates the content of a field from the AutoComplete dialog box, use the &lt;/em&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms536956%28VS.85%29.aspx"&gt;&lt;em&gt;onpropertychange&lt;/em&gt;&lt;/a&gt;&lt;em&gt; event, rather than the &lt;/em&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms536912%28VS.85%29.aspx"&gt;&lt;em&gt;onchange&lt;/em&gt;&lt;/a&gt;&lt;em&gt; event, because the &lt;strong&gt;onchange&lt;/strong&gt; event does not fire.&lt;/em&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;之前在測試開發階段，因偷懶加掛了One Click自動填表功能對手動測不多；而更早的手動測試階段，雖然曾反覆輸入不同值做測試，因表單沒有Submit，並不會納入自動完成提示清單(When a user submits a form, the name, value, and domain of the form component are encrypted for safekeeping)，因此還是錯失&amp;quot;以自動完成輸入&amp;quot;的機會。&lt;/p&gt; &lt;p&gt;事件成因清楚了，要解決就不難。我想到幾種做法:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;利用&amp;lt;input autocomplete=&amp;quot;off&amp;quot; /&amp;gt;關閉自動完成功能。  &lt;li&gt;改用blur取代change，但缺點是輸入值未變時也會觸發不必要的連動邏輯。  &lt;li&gt;用onpropertychange取代onchange，但缺點是會有跨瀏覽器問題，再不然就是針對IE加Javascript針對不同瀏覽器採行不同的做法。(鄉親吶~~ 看清楚，這就是跨瀏覽器要付出的代價呀!)&lt;/li&gt;&lt;/ol&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5955" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Javascript/default.aspx">Javascript</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Trouble-Shooting/default.aspx">Trouble-Shooting</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/IE/default.aspx">IE</category></item><item><title>生活瑣記-201001</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/25/life-twitter-201001.aspx</link><pubDate>Sun, 24 Jan 2010 15:30:31 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5943</guid><dc:creator>Jeffrey</dc:creator><slash:comments>1</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt;  &lt;ul&gt;   &lt;li&gt;自從有了DSLR胡亂玩了好些年，也不乏曾為追逐天晴大景背著沈重相機搶登山巔，      &lt;br /&gt;總以為要有好照片少不了景好技術佳加上老天賞臉，      &lt;br /&gt;直到前幾天，用老爺CASIO相機拍下這張半糊的照片，       &lt;br /&gt;我才驀然發現，      &lt;br /&gt;其實，照片是否引起悸動挑動心絃，無關乎構圖快門或光圈...       &lt;br /&gt;      &lt;br /&gt;&lt;img src="http://blog.darkthread.net/photos/darkthread/images/5940/original.aspx" alt="" /&gt;       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;幫兒子洗澡時，他好奇地摸著自己的&amp;quot;蛋蛋&amp;quot;誠心發問: 這個是做什麼用的呀?      &lt;br /&gt;鄉親吶~~~ 在黑暗浴室臨時舉辦的【&lt;a href="http://zh.wikipedia.org/wiki/%E7%99%BE%E8%90%AC%E5%B0%8F%E5%AD%B8%E5%A0%82"&gt;百萬小學堂&lt;/a&gt;】，關於這道【 大班 自然與生活科技】問題，你會怎麼回答呢?       &lt;br /&gt;(計分標準: 需以五歲小朋友可以理解的語言傳達正確知識，搞笑胡扯搪塞迴避者不予計分。另因臨時舉辦，故小西瓜、大力都沒來，所以也沒有好人卡、團結卡、知識卡可以用囉...)       &lt;br /&gt;至於我的答案? 先賣個關子，寫在文末。       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;車子的大燈壞了一顆，看在車主手冊有寫拆裝步驟的分上，決定自己賺工錢。     &lt;br /&gt;在網站比了價(幸好有先做功課，查到網購價最低140，老闆原本想唬我燈泡價位不可能這麼低)，在汽車材料行花150元買了一顆歐司朗H1，花了點時間模索... 哇哈哈! &lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/04/05/dark-plumber.aspx"&gt;黑暗水電工&lt;/a&gt;邁出挑戰【黑暗修車工】的第一步囉!      &lt;br /&gt;&lt;img class="PopBoxImageSmall" src="http://blog.darkthread.net/photos/darkthread/images/5942/secondarythumb.aspx" alt="" /&gt;       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;陽台上有一棵種了兩年的&lt;a href="http://blog.sina.com.tw/jenq6139/article.php?pbgid=14092&amp;amp;entryid=576549"&gt;香水檸檬&lt;/a&gt;，原本是跟花販買的小盆裁，入手時就帶了一棵拳頭大小的果實。      &lt;br /&gt;據說它是極好種的植物，隨便養都能果實纍纍。無奈放在陽台日照不足，加上平時也沒在園藝下功夫，在咱們家隨便種的結果，就是它也敷衍長。兩年來下再多肥料也只長葉子，開花次數用一隻手都可以數出來，更甭提結果實。所幸半年前有兩朵花順利修得正果，結出香水檸檬來。      &lt;br /&gt;這讓人頗有老來得子的振奮感，當然就捨不得摘，日益變大之際還怕樹枝不堪負荷，在下面墊了個玻璃瓶權充嬰兒椅。這陣子果實開始變黃，看來己熟透，摘下前特地拍照一張留念。      &lt;br /&gt;圖中有個一元硬幣可當比例尺，讓大家感受一下它的體積。其實也還好啦，還是像拳頭一般大，只是這回是像&amp;quot;砂鍋大的拳頭&amp;quot;一樣大，很強吧? XD       &lt;br /&gt;&lt;img src="http://blog.darkthread.net/photos/darkthread/images/5941/original.aspx" alt="" /&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;百萬小學堂的【 大班 自然與生活科技】問題大家有解答了嗎? 在此公佈黑暗版的答案:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#ff8000"&gt;&amp;quot;這是用來裝生小孩【種子】的地方，你要保護好哦!&amp;quot;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;兒子想起在開心農場種馬鈴薯播種發芽的過程，很滿意地點點頭，還自行演繹出&lt;font color="#ff8000"&gt;&amp;quot;哦! 所以把種子放到女生的肚子裡，就可生小Baby囉!&amp;quot;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;怎樣，這個比喻超讚吧?&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5943" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Life/default.aspx">Life</category></item><item><title>CODE-列舉元素已掛載的jQuery事件</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/23/list-jquery-events.aspx</link><pubDate>Fri, 22 Jan 2010 22:37:35 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5939</guid><dc:creator>Jeffrey</dc:creator><slash:comments>0</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;開發程式時偵錯的需求，想確認預期的事件函數是否已正確bind到元素上? &lt;/p&gt; &lt;p&gt;直覺想法是去查詢jQuery內部物件，列出已經掛載的事件函數。追了一下原始程式，發現jQuery會把各元素的事件保存在jQuery.data(elem, &amp;quot;events&amp;quot;)，而events裡又會為不同事件(例如: click, dblclick, load)各宣告一個handlers，放入events[eventType]；由於我們可以對同一事件宣告多個事件函數，因此handlers中會以handlers[handlerId]的方式保存事件函數。&lt;/p&gt; &lt;p&gt;看起來很抽象，跑一次範例便一目瞭然:&lt;/p&gt; &lt;div class="BlogCodeBlock"&gt; &lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;$(&lt;span class="str"&gt;&amp;quot;div&amp;quot;&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;.click(&lt;span class="kwrd"&gt;function&lt;/span&gt;() { alert(&lt;span class="str"&gt;&amp;quot;Click 1&amp;quot;&lt;/span&gt;); })&lt;/pre&gt;&lt;pre class="alt"&gt;.click(&lt;span class="kwrd"&gt;function&lt;/span&gt;() { alert(&lt;span class="str"&gt;&amp;quot;Click 2&amp;quot;&lt;/span&gt;); })&lt;/pre&gt;&lt;pre&gt;.dblclick(&lt;span class="kwrd"&gt;function&lt;/span&gt;() { alert(&lt;span class="str"&gt;&amp;quot;DblClick&amp;quot;&lt;/span&gt;); });&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; handlers = jQuery.data($(&lt;span class="str"&gt;&amp;quot;div&amp;quot;&lt;/span&gt;)[0], &lt;span class="str"&gt;&amp;quot;events&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; sb = [];&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; t &lt;span class="kwrd"&gt;in&lt;/span&gt; handlers)&lt;/pre&gt;&lt;pre&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;    sb.push(&lt;span class="str"&gt;&amp;quot;*EventType=&amp;quot;&lt;/span&gt; + t);&lt;/pre&gt;&lt;pre&gt;    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; h &lt;span class="kwrd"&gt;in&lt;/span&gt; handlers[t])&lt;/pre&gt;&lt;pre class="alt"&gt;        sb.push(&lt;span class="str"&gt;&amp;quot;    HandlerId[&amp;quot;&lt;/span&gt; + h + &lt;span class="str"&gt;&amp;quot;]-&amp;gt;&amp;quot;&lt;/span&gt; + handlers[t][h]);&lt;/pre&gt;&lt;pre&gt;}&lt;/pre&gt;&lt;pre class="alt"&gt;alert(sb.join(&lt;span class="str"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;));&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可得結果如下: (程式裡所謂HandlerId是一個流水號，是jQuery.event物件為每個事件函數所賦與不重複的編號) 
&lt;blockquote&gt;
&lt;p&gt;&lt;font color="#ff8000"&gt;*EventType=click&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; HandlerId[3]-&amp;gt;function() { alert(&amp;quot;Click 1&amp;quot;); }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; HandlerId[4]-&amp;gt;function() { alert(&amp;quot;Click 2&amp;quot;); }&lt;br /&gt;*EventType=dblclick&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; HandlerId[5]-&amp;gt;function() { alert(&amp;quot;DblClick&amp;quot;); }&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;實地測試，這個做法在jQuery-1.3.2或jQuery-1.4下都是可行的。但在jQuery 1.4下HandlerId會從1起跳，背後原因是jQuery-1.4取消了原本在bindReady()裡jQuery.event.add( window, &amp;quot;load&amp;quot;, jQuery.ready );，以及防止IE Memory Leak的邏輯中改用attachEvent取代jQuery( window ).bind( &amp;#39;unload&amp;#39;, ...);，少了兩個系統內建事件函數，自訂事件函數序號變成從1開始。&lt;/p&gt;
&lt;p&gt;【註】以上的做法列舉範圍只限透過jQuery.bind方式宣告的事件函數。&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5939" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/jQuery/default.aspx">jQuery</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/CODE/default.aspx">CODE</category></item><item><title>用.NET展現多核威力(3) – 佛心TPL之Parallel.For好威</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/22/multicore-3.aspx</link><pubDate>Thu, 21 Jan 2010 20:06:00 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5932</guid><dc:creator>Jeffrey</dc:creator><slash:comments>7</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt;  &lt;p&gt;在&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/03/multicore-2.aspx"&gt;前一篇文章&lt;/a&gt;裡，我們驗證了為每個CPU Core開一條獨立Thread並事先分攤好計算工作，可以讓巨量Log10計算程式飆出最高效能! 但是，仔細看看程式碼:&lt;/p&gt;  &lt;div class="BlogCodeBlock"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;int&lt;/span&gt; WORKER_COUNT = 2;&lt;/pre&gt;

    &lt;pre&gt;Thread[] workers = &lt;span class="kwrd"&gt;new&lt;/span&gt; Thread[WORKER_COUNT];&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;int&lt;/span&gt; jobsCountPerWorker = MAX_COUNT / WORKER_COUNT;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; WORKER_COUNT; i++)&lt;/pre&gt;

    &lt;pre class="alt"&gt;{&lt;/pre&gt;

    &lt;pre&gt;    &lt;span class="kwrd"&gt;int&lt;/span&gt; st = jobsCountPerWorker * i;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;int&lt;/span&gt; ed = jobsCountPerWorker * (i + 1);&lt;/pre&gt;

    &lt;pre&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (ed &amp;gt; MAX_COUNT) ed = MAX_COUNT;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    workers[i] = &lt;span class="kwrd"&gt;new&lt;/span&gt; Thread(() =&amp;gt;&lt;/pre&gt;

    &lt;pre&gt;    {&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; j = st; j &amp;lt; ed; j++)&lt;/pre&gt;

    &lt;pre&gt;        {&lt;/pre&gt;

    &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;double&lt;/span&gt; d = Math.Log10(Convert.ToDouble(j));&lt;/pre&gt;

    &lt;pre&gt;        }&lt;/pre&gt;

    &lt;pre class="alt"&gt;    });&lt;/pre&gt;

    &lt;pre&gt;    workers[i].Start();&lt;/pre&gt;

    &lt;pre class="alt"&gt;}&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; WORKER_COUNT; i++)&lt;/pre&gt;

    &lt;pre class="alt"&gt;    workers[i].Join();&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;我們寫了近20行的程式碼，而且還得花腦筋寫邏輯分割工作給多條Thread，要曉得如何用Thread.Join同步完成時間。說實在話，沒有三兩三，恐怕沒膽玩。&lt;/p&gt;

&lt;p&gt;如果我說有一種很簡單的新寫法可以實現類似的效果:&lt;/p&gt;

&lt;div class="BlogCodeBlock"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;Parallel.For(0, MAX_COUNT, j =&amp;gt;&lt;/pre&gt;

    &lt;pre&gt;{&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;double&lt;/span&gt; d = Math.Log10(Convert.ToDouble(j));&lt;/pre&gt;

    &lt;pre&gt;});&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;看到這裡，&lt;font size="2" color="#ff8000"&gt;大家會不會有想起立鼔掌的衝動?&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;這是.NET Framework 4.0裡內建的&lt;a href="http://msdn.microsoft.com/en-us/library/dd460717%28VS.100%29.aspx"&gt;Task Parallel Library(TPL)&lt;/a&gt;，一組幫助程式新手的佛心API。把原本複雜的多執行緒運算程式簡化成一行打死，寫程式的人就算對Thread.Join、lock()、ManualResetEvent一無所悉，照樣可以寫出漂亮的平行運算程式。(這下子，程式老鳥又有一項優勢被剝奪了，被菜鳥幹掉的日子愈來愈近了，我好怕...)&lt;/p&gt;

&lt;p&gt;依我個人的理解，TPL強調的是平行運算的能力，目的在搾乾每一滴CPU運算能力。它在概念上介於ThreadPool與自行管理數條Thread之間，最精彩的地方是會依CPU的負載狀況自動調節Thread數，直到所有CPU使用率都飆上100%，系統運算能力完全被榨乾為止。換句話說，一開始迴圈只啟動一條Thread，接著會在資源允許的前題下增加平行處理的Thread數(the loop starts with a degree of 1, and may work its way up to any maximum that’s specified as resources become available，&lt;a href="http://blogs.msdn.com/pfxteam/archive/2009/05/29/9655514.aspx"&gt;參考&lt;/a&gt;)。&lt;/p&gt;

&lt;p&gt;接著，我們就讓原來寫法跟Parallel.For車拼一下(測試平台為E6400雙核CPU): (註: 要體驗.NET 4.0，請先&lt;a href="http://msdn.microsoft.com/en-us/vstudio/dd582936.aspx"&gt;下載VS2010 Beta&lt;/a&gt;回家玩)&lt;/p&gt;

&lt;div class="BlogCodeBlock"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Diagnostics;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Threading;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Threading.Tasks;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; MultiCore&lt;/pre&gt;

    &lt;pre class="alt"&gt;{&lt;/pre&gt;

    &lt;pre&gt;    &lt;span class="kwrd"&gt;class&lt;/span&gt; TestParalleFor&lt;/pre&gt;

    &lt;pre class="alt"&gt;    {&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;

    &lt;pre class="alt"&gt;        {&lt;/pre&gt;

    &lt;pre&gt;            &lt;span class="kwrd"&gt;int&lt;/span&gt; MAX_COUNT = 5000 * 10000;&lt;/pre&gt;

    &lt;pre class="alt"&gt;            Stopwatch sw = &lt;span class="kwrd"&gt;new&lt;/span&gt; Stopwatch();&lt;/pre&gt;

    &lt;pre&gt;            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; round = 0; round &amp;lt; 3; round++)&lt;/pre&gt;

    &lt;pre class="alt"&gt;            {&lt;/pre&gt;

    &lt;pre&gt;                sw.Reset();&lt;/pre&gt;

    &lt;pre class="alt"&gt;                sw.Start();&lt;/pre&gt;

    &lt;pre&gt;                &lt;span class="kwrd"&gt;int&lt;/span&gt; WORKER_COUNT = 2;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                Thread[] workers = &lt;span class="kwrd"&gt;new&lt;/span&gt; Thread[WORKER_COUNT];&lt;/pre&gt;

    &lt;pre&gt;                &lt;span class="kwrd"&gt;int&lt;/span&gt; jobsCountPerWorker = MAX_COUNT / WORKER_COUNT;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; WORKER_COUNT; i++)&lt;/pre&gt;

    &lt;pre&gt;                {&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    &lt;span class="kwrd"&gt;int&lt;/span&gt; st = jobsCountPerWorker * i;&lt;/pre&gt;

    &lt;pre&gt;                    &lt;span class="kwrd"&gt;int&lt;/span&gt; ed = jobsCountPerWorker * (i + 1);&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (ed &amp;gt; MAX_COUNT) ed = MAX_COUNT;&lt;/pre&gt;

    &lt;pre&gt;                    workers[i] = &lt;span class="kwrd"&gt;new&lt;/span&gt; Thread(() =&amp;gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    {&lt;/pre&gt;

    &lt;pre&gt;                        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; j = st; j &amp;lt; ed; j++)&lt;/pre&gt;

    &lt;pre class="alt"&gt;                        {&lt;/pre&gt;

    &lt;pre&gt;                            &lt;span class="kwrd"&gt;double&lt;/span&gt; d = Math.Log10(Convert.ToDouble(j));&lt;/pre&gt;

    &lt;pre class="alt"&gt;                        }&lt;/pre&gt;

    &lt;pre&gt;                    });&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    workers[i].Start();&lt;/pre&gt;

    &lt;pre&gt;                }&lt;/pre&gt;

    &lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; WORKER_COUNT; i++)&lt;/pre&gt;

    &lt;pre&gt;                    workers[i].Join();&lt;/pre&gt;

    &lt;pre class="alt"&gt;                sw.Stop();&lt;/pre&gt;

    &lt;pre&gt;                Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Multi-Thread[{1}] = {0:N0}ms&amp;quot;&lt;/span&gt;, &lt;/pre&gt;

    &lt;pre class="alt"&gt;                    sw.ElapsedMilliseconds, WORKER_COUNT);&lt;/pre&gt;

    &lt;pre&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                sw.Reset();&lt;/pre&gt;

    &lt;pre&gt;                sw.Start();&lt;/pre&gt;

    &lt;pre class="alt"&gt;                Parallel.For(0, MAX_COUNT, j =&amp;gt;&lt;/pre&gt;

    &lt;pre&gt;                {&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    &lt;span class="kwrd"&gt;double&lt;/span&gt; d = Math.Log10(Convert.ToDouble(j));&lt;/pre&gt;

    &lt;pre&gt;                });&lt;/pre&gt;

    &lt;pre class="alt"&gt;                sw.Stop();&lt;/pre&gt;

    &lt;pre&gt;                Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Parallel.For = {0:N0}ms&amp;quot;&lt;/span&gt;,&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    sw.ElapsedMilliseconds);&lt;/pre&gt;

    &lt;pre&gt;            }&lt;/pre&gt;

    &lt;pre class="alt"&gt;            Console.Read();&lt;/pre&gt;

    &lt;pre&gt;        }&lt;/pre&gt;

    &lt;pre class="alt"&gt;    }&lt;/pre&gt;

    &lt;pre&gt;}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;font color="#ff8000"&gt;Multi-Thread[2] = 2,003ms 
      &lt;br /&gt;Parallel.For = 2,119ms 

      &lt;br /&gt;Multi-Thread[2] = 2,098ms 

      &lt;br /&gt;Parallel.For = 2,283ms 

      &lt;br /&gt;Multi-Thread[2] = 1,966ms 

      &lt;br /&gt;Parallel.For = 2,113ms&lt;/font&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;就數據而言，二者相近，但在這個例子中，大部分的時間Parallel.For還是略輸一籌。理由是Parallel.For強調的是動態調節，由一條Thread開始，再逐步增加，自然會比事先規劃好全程用兩條Thread衝刺慢一些。不過別沮喪，我們動個手腳，馬上就能還Parallel.For一個公道。&lt;/p&gt;

&lt;p&gt;我們將:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;font color="#00ff00"&gt;double d = Math.Log10(Convert.ToDouble(j));&lt;/font&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;改成每5000次Delay 10ms: (假裝在等待某項非CPU資源)&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;font color="#00ff00"&gt;double d = Math.Log10(Convert.ToDouble(j)); 
      &lt;br /&gt;if (j % 5000 == 0) Thread.Sleep(10);&lt;/font&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;並把執行次數改為100萬次縮短總執行時間。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;font color="#ff8000"&gt;Multi-Thread[2] = 1,046ms 
      &lt;br /&gt;Parallel.For = 652ms 

      &lt;br /&gt;Multi-Thread[2] = 1,009ms 

      &lt;br /&gt;Parallel.For = 502ms 

      &lt;br /&gt;Multi-Thread[2] = 1,007ms 

      &lt;br /&gt;Parallel.For = 550ms&lt;/font&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;怎樣? 前一個測試二者結果相近，加入Thread.Sleep後比原來的一核一緒寫法快了近一倍，程式簡潔N倍，在這兩回合比試中，我認定Parallel.For明顯勝出!!&lt;/p&gt;

&lt;p&gt;因為Thread.Sleep的加入會降低CPU使用率，Parallel.For動態增加Thead的能力便可派上用場，填補了CPU空檔，也就縮短了總執行時間。在實務上，即便是以運算為主的工作，還是免不了有等待I/O、等待其他Thread就緒的同步需求，必須暫停等待其他非CPU資源後再繼續，等待期間會產生CPU使用率下降的情況。平行運算哲學中，讓CPU閒著是一種罪惡，在CPU使用率未達100%時增加Thread數充分利用閒置的運算能力，自然會比一核一緒更上一層樓。要自己寫出視CPU使用率動態調節Thread數的程式並非易事，而Parallel.For可以幫我們做到這一點，很威吧? 大家如果在.NET 4.0中開發類似的平行運算需求時，千萬不要錯過它囉~~&lt;/p&gt;&lt;p&gt;&lt;font color="#ff6600"&gt;[2010-02-05補充] &lt;/font&gt;若想在.NET 3.5中使用 Parallel.For()，可以參考&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/02/05/tpl-for-3-5.aspx"&gt;這篇文章&lt;/a&gt;。&lt;br /&gt;&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5932" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/.NET/default.aspx">.NET</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Performance/default.aspx">Performance</category></item><item><title>NOTES-客製化Sharepoint查詢研究筆記</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/21/sharepoint-search-notes.aspx</link><pubDate>Thu, 21 Jan 2010 07:18:00 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5929</guid><dc:creator>Jeffrey</dc:creator><slash:comments>0</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt;
&lt;p&gt;最近工作上遇到需要客製Sharepoint查詢的需求，這篇主要是研究過程的隨手筆記，避免明天一覺醒來忘到一乾二淨。由於內容較雜亂無章，請讀者自行斟酌是否要直接略過。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文件: &lt;a href="http://sharepoint-sezai-moss-2007.blogspot.com/2008/02/moss-2007-custom-search.html"&gt;MOSS 2007 Custom Search&lt;/a&gt; 
&lt;ol&gt;
&lt;li&gt;先考慮用現成Search，可以節省大把時間。SPS2007已經比SPS2003先進方便很多--Business Data Content(BDC)。 
&lt;li&gt;真需客製時可用&lt;a href="http://msdn2.microsoft.com/en-us/library/microsoft.office.server.search.query.aspx"&gt;Microsoft.Office.Server.Search.Query&lt;/a&gt;建立WebPart 
&lt;li&gt;跨系統搜索(例如: SPS, CMS)的做法&lt;br /&gt;1) 建立BDC Application Definition, 匯入SSP(Shared Services Provider)。其中要實作ProductIDEnumerator method，用來傳回Primary Key，讓Sharepoint可以用它讀資料回來做Index。&lt;br /&gt;2) 匯入時會建立BDC Entities的網頁，可用來檢視資料是否正確匯入。&lt;br /&gt;3) 在SSP中加入DBC Source，開始Crawl&lt;br /&gt;4) 建立&lt;a href="http://msdn.microsoft.com/en-us/library/ms497276.aspx"&gt;自訂屬性&lt;/a&gt;對應到爬回來的屬性，加入一些進偕搜尋可以用來篩選的條件(Mapping時可設定順位，若沒A，用B)&lt;br /&gt;5) 重新再爬一次，這次會對應回Managed Properties。&lt;br /&gt;6) 自訂搜尋吧! 有三種方法:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * Keyword Query syntax (直接送給Enterprise Search service)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * SQL syntax (加料式SQL語法)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * URL syntax (直接串連搜尋介面網頁) 
&lt;li&gt;SQL法範例:&lt;br /&gt;&lt;font color="#00ff00"&gt;SELECT&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Title, Path, Description, HitHighlightedSummary, Rank, ProductMembershipRank, DomesticRegion, ProductCategory &lt;br /&gt;FROM&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SCOPE() &lt;br /&gt;WHERE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FREETEXT(Description,&amp;#39;Fun&amp;#39;) AND ProductCategory = &amp;#39;Accommodation&amp;#39; &lt;br /&gt;AND DomesticRegion = &amp;#39;Australia&amp;#39;&amp;#39;s South West&amp;#39; &lt;br /&gt;&lt;/font&gt;ORDER BY MembershipRank DESC, RANK DESC 
&lt;li&gt;SQL法的傳回結果:&lt;br /&gt;&lt;font color="#00ff00"&gt;FullTextSqlQuery ftsq = new FullTextSqlQuery(ServerContext.Current); ftsq.ResultTypes = ResultType.RelevantResults; &lt;br /&gt;ftsq.QueryText = &amp;lt;YOURQUERY&amp;gt;; &lt;br /&gt;//Return the search results to a ResultTableCollection，可視為DataSet用&lt;br /&gt;ResultTableCollection results = ftsq.Execute()&lt;/font&gt; 
&lt;li&gt;ResultTableCollection，可視為DataSet用，同時有ElapsedTime, HitHighlightedSummary等好用屬性。&lt;/li&gt;&lt;/ol&gt;
&lt;li&gt;官方文件: &lt;a href="http://msdn.microsoft.com/en-us/library/ms570748.aspx"&gt;Enterprise Search Architecture&lt;/a&gt; 
&lt;ul&gt;
&lt;li&gt;組成元件: Index Engine, Query Engine, Protocol Handlers(將不同管道取得的原始資料中的文件取出來), IFilters(取出文件中的文字內容與屬性), Content Index, Property Store, Search Configuration Data, Wordbreakers 
&lt;li&gt;Content Crawling: Filter Daemon使用Protocol Handler把資料取回來，用IFilter去取出其中的文字與Metadata，做全文檢索Index時會用到Workbreaker，Property與Index是分開存放的。Property存放處還一併記錄了文件層級的安控資訊。 
&lt;li&gt;Search Query Engine: 搜尋關鍵字會先經Wordbreaker處理。有加Property條件時，會先用Index查，再依查到結果去取回屬性資料做第二層篩選，沒權限的查詢結果項目也會被刪除。 
&lt;li&gt;支援的資料來源: Sharepoint Content, Web Content, File Share, Exchange Folder Content, Business Data Content 
&lt;li&gt;Shared Scopes: 用一些條件把內容項目定義成一個特定範圍，可用的Rule包含: Address, Property Query, Content Source 
&lt;li&gt;Document Property Mappings: 有兩種Property-Crawled Prop.及Managed Prop.，二者間可以設定Mapping。 
&lt;li&gt;Server Mapping: 可以設定查到的結果怎麼Mapping成特定的URL，例如: File Share -&amp;gt; Web Link 
&lt;li&gt;Revevance Inclusions: 計算Ranking，改變結果項目顯示順序，可能的參數包含: Click distance, Hyperlink anchor text, URL surf depth, URL text matching, Automated metadata extraction, Automatic language detection, File type relevancy biasing, Enhanced text analysis 
&lt;li&gt;File Type Inclusions: 決定Crawler哪些檔案類別要擷取哪些不要 
&lt;li&gt;Logging: Query Log, Crawl Log 
&lt;li&gt;Site Level的搜尋管理: Scope, Keyword and best bet&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;官方文件: &lt;a href="http://msdn.microsoft.com/en-us/library/ms561536.aspx"&gt;Building Enterprise Search Queries&lt;/a&gt; &lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Keywords 
&lt;ul&gt;
&lt;li&gt;關鍵字: Keyword1 +Keyword2 -Keyword3 
&lt;li&gt;屬性: &lt;br /&gt;&amp;lt;property name&amp;gt;:&amp;lt;value&amp;gt;&lt;br /&gt;&amp;lt;scope name&amp;gt;:&amp;lt;value&amp;gt;&lt;br /&gt;&amp;lt;collapsed results type&amp;gt;:&amp;lt;value&amp;gt; 
&lt;li&gt;屬性範例: site:http://blog.darkthread.net, author:&amp;quot;Jeffrey Lee&amp;quot;, scope:&amp;quot;ScopeName&amp;quot;, duplicate:http://&amp;lt;displayUrl&amp;gt;(這個看不懂) 
&lt;li&gt;查詢時，不會檢查URL, SiteName, File Ext，就是查不到東西&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;Enterprise Search SQL Language 
&lt;ul&gt;
&lt;li&gt;以ANSI-SQL為基礎 
&lt;li&gt;不一定要精確，例如: program &amp;lt;-&amp;gt; programming 
&lt;li&gt;rank欄位會傳回吻合度，0-1000 
&lt;li&gt;有些(謎之聲: 這叫很多吧?)SQL語法不可用: CONVERT(但CAST可以)、CREATE VIEW、DATASOURCE、AVG(), COUNT(), MAX(), MIN(), SUM(), GRANT, INSERT, CONTAINS, LIKE, MATCHES, 關聯欄位相比較(不會吧?), Parameter, REVOKE, SCOPE, SELECT ALL, Stored Procedure, UNKNOWN, UPDATE, BATCH... 
&lt;li&gt;要指定Scope =&amp;gt; SELECT ... FROM Scope() WHERE &amp;quot;scope&amp;quot; = &amp;quot;All Sites&amp;quot;... 
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms513993.aspx"&gt;CINTAINS&lt;/a&gt;精確比對，&lt;a href="http://msdn.microsoft.com/en-us/library/ms516214.aspx"&gt;FREETEXT&lt;/a&gt;類似比對 
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms500785.aspx"&gt;LIKE&lt;/a&gt;, string/date/timestamp/numeric可以用&lt;a href="http://msdn.microsoft.com/en-us/library/ms541692.aspx"&gt;大小於比對&lt;/a&gt;, NULL代表未定義 
&lt;li&gt;WHERE LastModifiedTime &amp;lt;=DATEADD (DAY, -2, DATEADD (HOUR, -4, GETGMTDATE())) 
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms519727.aspx"&gt;ARRAY [1,2] &amp;lt; ARRAY [1,2,3]&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;URL法 
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/aa637082.aspx"&gt;參數&lt;/a&gt;: k-關鍵字, s-Scope, v=date or relevance, start=頁數&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms544561.aspx"&gt;Enterprise Search Query Object Model&lt;/a&gt; 
&lt;ul&gt;
&lt;li&gt;Web Part or ASPX 
&lt;li&gt;Microsoft.Office.Server.dll, Microsoft.Office.Server.Search.dll, Microsoft.SharePoint.dll 
&lt;li&gt;物件 
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.office.server.search.query.query.aspx"&gt;Query&lt;/a&gt;&amp;nbsp; 內部用，請用以下二選一 
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.office.server.search.query.fulltextsqlquery.aspx"&gt;FullTextSqlQuery&lt;/a&gt;&amp;nbsp; SQL查詢 
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.office.server.search.query.keywordquery.aspx"&gt;KeywordQuery&lt;/a&gt; Keyword語法&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;用哪一個物件? 複雜時KeywordQuery會無法勝任，就用FullTextSqlQuery &lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms543175.aspx"&gt;Web Service&lt;/a&gt;: httq://Server_Name/[sites/][Site_Name/]_vti_bin/search.asmx 
&lt;ul&gt;
&lt;li&gt;Query只傳回Title, Desc, Date, Relevance，QueryEx還可傳回Rank, Author, Size, Path...等。 
&lt;li&gt;QueryEx傳回DataSet!! (Yahoo~~~)&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;自訂結果存取權限管控，決定User該不該看到該筆查詢: &lt;a href="http://msdn.microsoft.com/en-us/library/aa981236.aspx"&gt;ISecurityTrimmer&lt;/a&gt; 
&lt;li&gt;客製查詢結果: &lt;a href="http://msdn.microsoft.com/en-us/library/ms550732.aspx"&gt;修改XSLT&lt;/a&gt; 
&lt;li&gt;客製查詢中心 
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms491453.aspx"&gt;寫程式管理&lt;/a&gt;Search Content、Metadata、Scope、Keyword... 
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc806030.aspx"&gt;Featured Search&lt;/a&gt;: 在查詢結果中混入其他來源的結果(置入性行銷?)&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;佛心來著的&lt;a href="http://sharepointsearchserv.codeplex.com/"&gt;Sharepoint Search Service Tool&lt;/a&gt;: 可以輔助產生Query Syntax、馬上看結果的好東西&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5929" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Sharepoint/default.aspx">Sharepoint</category></item><item><title>用.NET展現多核威力(2A) - 一核一緒補充包</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/20/multicore-2a.aspx</link><pubDate>Tue, 19 Jan 2010 21:00:00 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5922</guid><dc:creator>Jeffrey</dc:creator><slash:comments>3</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt;
&lt;p&gt;在&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/03/multicore-2.aspx"&gt;前一篇多核研討文章&lt;/a&gt;中，用了一個計算1000萬次Log10運算的範例驗證Thread數與Core相同時可以達到最佳效能，網友Google質疑以Log10計算當範例是否用能代表&amp;quot;以運算為主的大量作業&amp;quot;，在此做點補充說明。&lt;/p&gt;
&lt;p&gt;我想若以茶包射手實事求是的精神，&amp;quot;以運算為主的大量作業&amp;quot;這個命題是有問題的，應該要修正成&amp;quot;不涉及非CPU資源競爭的大量純運算作業&amp;quot;更貼近原意。用白話來解釋，這裡假設的前題是---有一大堆運算工作要處理，每件運算工作彼此獨立可以同時進行，且每件運算所需的資料自給自足，不需要排隊讀取/寫入記憶體、磁碟、網路等資源。當此前題成立，理論上連續大量運算就會耗光單一CPU的所有運算資源，讓CPU呈現100%佔用狀態。因此不管是&amp;quot;簡單的Log10計算&amp;quot;或是&amp;quot;複雜的超大矩陣運算&amp;quot;應該都能得到相同的結果--要達到最高效能，就是讓每顆CPU都忙到最高點，並避免Thread過多時要耗費CPU去做&lt;a href="http://en.wikipedia.org/wiki/Context_switch"&gt;Context Switch&lt;/a&gt;拖累效能。以這個概念演繹，為每一核安排一條執行緒應為最佳解。&lt;/p&gt;
&lt;p&gt;補充完前回理論命題的不足，我們也來試一下&amp;quot;矩陣運算的範例&amp;quot;，看看是否可以獲得一核一緒的結論?&lt;/p&gt;
&lt;p&gt;不想自己造輪子，這裡用現成&amp;quot;內含&lt;a href="http://www.tropsoft.com/strongenc/des.htm"&gt;小型矩陣運算&lt;/a&gt;的DES加密&amp;quot;當作範例，但複雜度己比Log10高出許多。我用亂數產生了1000個長度為512KB的byte[]，分別用1-16條的Thread分工合作處理對這1000筆資料做DES加密，不同Thread數的測試各做五次，取其總耗用時間的平均值。&lt;/p&gt;
&lt;div class="BlogCodeBlock"&gt;
&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Diagnostics;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Threading;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Security.Cryptography;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.IO;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; MultiCore&lt;/pre&gt;&lt;pre&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;class&lt;/span&gt; ComplexCalc&lt;/pre&gt;&lt;pre&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;&lt;pre&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;int&lt;/span&gt; MAX_COUNT = 1000;&lt;/pre&gt;&lt;pre&gt;            Dictionary&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;, &lt;span class="kwrd"&gt;byte&lt;/span&gt;[]&amp;gt; pool = &lt;span class="kwrd"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;, &lt;span class="kwrd"&gt;byte&lt;/span&gt;[]&amp;gt;();&lt;/pre&gt;&lt;pre class="alt"&gt;            Random rnd = &lt;span class="kwrd"&gt;new&lt;/span&gt; Random();&lt;/pre&gt;&lt;pre&gt;            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; MAX_COUNT; i++)&lt;/pre&gt;&lt;pre class="alt"&gt;            {&lt;/pre&gt;&lt;pre&gt;                &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] b = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[512 * 1024];&lt;/pre&gt;&lt;pre class="alt"&gt;                rnd.NextBytes(b);&lt;/pre&gt;&lt;pre&gt;                pool.Add(i, b);&lt;/pre&gt;&lt;pre class="alt"&gt;            }&lt;/pre&gt;&lt;pre&gt;            &lt;span class="kwrd"&gt;int&lt;/span&gt; ROUND_COUNT = 5;&lt;/pre&gt;&lt;pre class="alt"&gt;            Stopwatch sw = &lt;span class="kwrd"&gt;new&lt;/span&gt; Stopwatch();&lt;/pre&gt;&lt;pre&gt;            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; WORKER_COUNT = 1; WORKER_COUNT &amp;lt; 16; WORKER_COUNT++)&lt;/pre&gt;&lt;pre class="alt"&gt;            {&lt;/pre&gt;&lt;pre&gt;                &lt;span class="kwrd"&gt;long&lt;/span&gt; sum = 0;&lt;/pre&gt;&lt;pre class="alt"&gt;                List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; detail = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;();&lt;/pre&gt;&lt;pre&gt;                &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; round = 0; round &amp;lt; ROUND_COUNT; round++)&lt;/pre&gt;&lt;pre class="alt"&gt;                {&lt;/pre&gt;&lt;pre&gt;                    sw.Reset();&lt;/pre&gt;&lt;pre class="alt"&gt;                    sw.Start();&lt;/pre&gt;&lt;pre&gt;                    Thread[] workers = &lt;span class="kwrd"&gt;new&lt;/span&gt; Thread[WORKER_COUNT];&lt;/pre&gt;&lt;pre class="alt"&gt;                    &lt;span class="kwrd"&gt;int&lt;/span&gt; jobsCountPerWorker = MAX_COUNT / WORKER_COUNT;&lt;/pre&gt;&lt;pre&gt;                    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; WORKER_COUNT; i++)&lt;/pre&gt;&lt;pre class="alt"&gt;                    {&lt;/pre&gt;&lt;pre&gt;                        &lt;span class="kwrd"&gt;int&lt;/span&gt; st = jobsCountPerWorker * i;&lt;/pre&gt;&lt;pre class="alt"&gt;                        &lt;span class="kwrd"&gt;int&lt;/span&gt; ed = jobsCountPerWorker * (i + 1);&lt;/pre&gt;&lt;pre&gt;                        &lt;span class="kwrd"&gt;if&lt;/span&gt; (ed &amp;gt; MAX_COUNT) ed = MAX_COUNT;&lt;/pre&gt;&lt;pre class="alt"&gt;                        workers[i] = &lt;span class="kwrd"&gt;new&lt;/span&gt; Thread(() =&amp;gt;&lt;/pre&gt;&lt;pre&gt;                        {&lt;/pre&gt;&lt;pre class="alt"&gt;                            DESCryptoServiceProvider des =&lt;/pre&gt;&lt;pre&gt;                                &lt;span class="kwrd"&gt;new&lt;/span&gt; DESCryptoServiceProvider();&lt;/pre&gt;&lt;pre class="alt"&gt;                            des.Key = Encoding.UTF8.GetBytes(&lt;span class="str"&gt;&amp;quot;ABCDEFGH&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;                            des.Key = Encoding.UTF8.GetBytes(&lt;span class="str"&gt;&amp;quot;12345678&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;                            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; j = st; j &amp;lt; ed; j++)&lt;/pre&gt;&lt;pre&gt;                            {&lt;/pre&gt;&lt;pre class="alt"&gt;                                &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] randomContent = pool[j];&lt;/pre&gt;&lt;pre&gt;                                &lt;span class="kwrd"&gt;using&lt;/span&gt; (MemoryStream ms = &lt;span class="kwrd"&gt;new&lt;/span&gt; MemoryStream())&lt;/pre&gt;&lt;pre class="alt"&gt;                                {&lt;/pre&gt;&lt;pre&gt;                                    &lt;span class="kwrd"&gt;using&lt;/span&gt; (CryptoStream cs = &lt;span class="kwrd"&gt;new&lt;/span&gt; CryptoStream(ms,&lt;/pre&gt;&lt;pre class="alt"&gt;                                        des.CreateEncryptor(), CryptoStreamMode.Write))&lt;/pre&gt;&lt;pre&gt;                                    {&lt;/pre&gt;&lt;pre class="alt"&gt;                                        cs.Write(randomContent, 0, randomContent.Length);&lt;/pre&gt;&lt;pre&gt;                                        cs.FlushFinalBlock();&lt;/pre&gt;&lt;pre class="alt"&gt;                                    }&lt;/pre&gt;&lt;pre&gt;                                }&lt;/pre&gt;&lt;pre class="alt"&gt;                            }&lt;/pre&gt;&lt;pre&gt;                        });                          &lt;/pre&gt;&lt;pre class="alt"&gt;                        workers[i].Start();&lt;/pre&gt;&lt;pre&gt;                    }&lt;/pre&gt;&lt;pre class="alt"&gt;                    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; WORKER_COUNT; i++)&lt;/pre&gt;&lt;pre&gt;                        workers[i].Join();&lt;/pre&gt;&lt;pre class="alt"&gt;                    sw.Stop();&lt;/pre&gt;&lt;pre&gt;                    sum += sw.ElapsedMilliseconds;&lt;/pre&gt;&lt;pre class="alt"&gt;                    detail.Add(sw.ElapsedMilliseconds.ToString());&lt;/pre&gt;&lt;pre&gt;                }&lt;/pre&gt;&lt;pre class="alt"&gt;                Console.WriteLine(&lt;span class="str"&gt;&amp;quot;平行處理[{1}] = {0:N0}ms [{2}]&amp;quot;&lt;/span&gt;,&lt;/pre&gt;&lt;pre&gt;                    sum / ROUND_COUNT, WORKER_COUNT, &lt;span class="kwrd"&gt;string&lt;/span&gt;.Join(&lt;span class="str"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;, detail.ToArray()));&lt;/pre&gt;&lt;pre class="alt"&gt;            }&lt;/pre&gt;&lt;pre&gt;            Console.Read();&lt;/pre&gt;&lt;pre class="alt"&gt;        }&lt;/pre&gt;&lt;pre&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;有幸借到一台8核CPU的神器，在上面測試得到的結果，應該可讓我們對&amp;quot;一核一緒&amp;quot;的推論更有信心。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;平行處理[1] = 14,838ms [14825,14804,14834,14913,14815] &lt;br /&gt;平行處理[2] = 7,942ms [7932,7781,8069,7992,7938] &lt;br /&gt;平行處理[3] = 5,224ms [5434,5234,5138,5160,5158] &lt;br /&gt;平行處理[4] = 3,976ms [3952,3941,3975,3959,4053] &lt;br /&gt;平行處理[5] = 3,312ms [3299,3322,3374,3305,3261] &lt;br /&gt;平行處理[6] = 2,900ms [2874,2905,2913,2915,2897] &lt;br /&gt;平行處理[7] = 2,615ms [2566,2646,2605,2670,2592] &lt;br /&gt;平行處理[8] = 2,540ms [2526,2449,2506,2566,2654] &lt;br /&gt;平行處理[9] = 2,641ms [2809,2588,2713,2522,2576] &lt;br /&gt;平行處理[10] = 2,726ms [2737,2706,2710,2809,2672] &lt;br /&gt;平行處理[11] = 2,684ms [2724,2638,2670,2625,2767] &lt;br /&gt;平行處理[12] = 2,771ms [2796,2795,2744,2717,2805] &lt;br /&gt;平行處理[13] = 2,755ms [2648,2764,2665,2710,2990] &lt;br /&gt;平行處理[14] = 2,726ms [2741,2705,2809,2711,2667] &lt;br /&gt;平行處理[15] = 2,781ms [2862,2686,2792,2837,2732]&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;陸續用過不同的演算內容(共同等徵是自給自足的純CPU運算不涉及其他資料共用)做相同測試，大致的結果都很相近--Thread數增加時，耗用時間會遞減，最短的時間會出現在Thread數與CPU核數相同時；而Thread超過CPU核數時，時間會略為增加，但並不會隨Thread數繼續上升而明顯增加，而是呈現隨機變化(以上為例: 11變快，12變慢，13又比12快，反覆做了幾次，發現其無一定規則)。針對這個觀察，我的解釋是，Thread數比CPU核數略多時，產生的Context Switch狀況有限，故對效能的影響也不大。經過多次實驗，耗用時間最短的數據出現在Thread數等於CPU核數這點倒是被獲得證實。&lt;/p&gt;
&lt;p&gt;平行運算是門深奧的學問，要深入探討學術理論遠超出一般程式開發人員的能力範圍。不過，依茶包射手的精神，在能力許可範圍親手實驗一下與自己切身相關的效能議題，體驗意想不到的樂趣有何不可? 上述的範例算是一個有趣的實驗基礎，稍加修改就可以用來驗證不同運算需求在不同核緒比例下的效能表現，有興趣的人可以玩玩，檢視一下不同運算需求的最佳核緒比例，也歡迎有不同心得的朋友分享切磋。&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5922" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/.NET/default.aspx">.NET</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Performance/default.aspx">Performance</category></item><item><title>邁入光纖時代囉~~</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/16/adsl-to-fiber.aspx</link><pubDate>Sat, 16 Jan 2010 00:31:41 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5908</guid><dc:creator>Jeffrey</dc:creator><slash:comments>0</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt;  &lt;p&gt;家裡的ADSL速率維持2M/256K的速率已經多年，由於平時沒有畜養動物的習慣，這個頻寬用來上網查資料、噗浪、讓家裡的兩位小自耕農栽種水果花卉... 倒是綽綽有餘。&lt;/p&gt;  &lt;p&gt;唯二小小不滿足，是發Mail上載大型附檔時常會被256K的上傳頻寬勒住，有種用吸管喝湯的不暢快感；還有在看YouTube影片時，每次只要按下HQ高畫質鈕，主角就會三不五時遭人點穴無法動彈，看了於心不忍。&lt;/p&gt;  &lt;p&gt;一直在等待高頻寬的價位平民化，去年底剛好看到現有ISP有個針對老客戶的資訊月特惠專案，升級成10MB/2MB，每個月大約多一百多塊，頻寬就可放大五倍，感覺上頗為划算，便提出申請。&lt;/p&gt;  &lt;p&gt;接獲通知要來裝機，特別在ADSL退休前，做個傳輸速度Benchmark，一方面留念，一方面好做為升級後的比較基準。(茶包射手格言: 建立衡量基準是Performance Tuning的&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2006/05/04/performance-tuning.aspx"&gt;第一步&lt;/a&gt;)&lt;/p&gt;  &lt;p&gt;2M/256K ADSL&lt;/p&gt;  &lt;p&gt;&lt;img class="PopBoxImageSmall" src="http://blog.darkthread.net/photos/darkthread/images/5904/500x375.aspx" alt="" /&gt; &lt;img class="PopBoxImageSmall" src="http://blog.darkthread.net/photos/darkthread/images/5905/500x375.aspx" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;10M/2M 光纖 &lt;/p&gt;  &lt;p&gt;&lt;img class="PopBoxImageSmall" src="http://blog.darkthread.net/photos/darkthread/images/5906/500x375.aspx" alt="" /&gt; &lt;img class="PopBoxImageSmall" src="http://blog.darkthread.net/photos/darkthread/images/5907/500x375.aspx" alt="" /&gt;&lt;/p&gt;  &lt;p&gt;依據升級頻寬前後下載同樣檔案的傳輸速率，算下來差不多真的提升約五倍。另外，看YouTube HQ也確實不再有停格卡住的狀況，感覺良好!&lt;/p&gt;  &lt;p&gt;從此正式宣佈，黑暗府堂堂邁入光纖時代囉~~~&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5908" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Life/default.aspx">Life</category></item><item><title>jQuery 1.4 小閱兵</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/16/jquery-1-4.aspx</link><pubDate>Fri, 15 Jan 2010 23:36:00 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5903</guid><dc:creator>Jeffrey</dc:creator><slash:comments>9</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt;
&lt;p&gt;為了歡度jQuery四歲生日(jQuery由John Resig 於 2006/01/14 在 BarCamp NYC 首次發表&lt;a href="http://msdn.microsoft.com/zh-tw/asp.net/dd446623.aspx"&gt;[註]&lt;/a&gt;)，jQuery開發團隊在2010/01/14釋出了&lt;a href="http://jquery14.com/day-01/jquery-14"&gt;jQuery 1.4版&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;簡單整理一下我所理解的1.4改版重點:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;大量重構常用的函數，降低程式複雜度(主要是減少內部函數彼此呼叫的次數)，達到改善效能的目標。 &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;.css(), .attr(), .val(), .html(), .text(), .append(), .prepend(), .before(), .after(), .replaceWith(), .wrap(), .wrapInner(), .offset(), .addClass(), .removeClass(), .toggleClass() 可傳入函數，由函數的傳回值當作參數值。(傳入函數當成參數的做法，有個術語叫Function Settter) &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;.css(), .attr(), .val(), .html(), .text(), .append(), .prepend(), .offset(), .addClass(), .removeClass(), .toggleClass() 在Function Setter時，該函數的第二個參數即原值。這點很方便，例如，如果要在所有的&amp;lt;a&amp;gt;顯示文字的後方加上&amp;quot;[L]&amp;quot;字串，過去會寫成: &lt;br /&gt;&lt;font color="#00ff00"&gt;$(&amp;quot;a”).each(function(i) { var $a = $(this); $a.html($a.html() + &amp;quot;[L]&amp;quot;); });&lt;/font&gt; &lt;br /&gt;現在可以結合2, 3點的新功能，寫成: &lt;br /&gt;&lt;font color="#00ff00"&gt;$(&amp;quot;a”).html(function(i, html) { return html + “[L]”; });&lt;/font&gt; &lt;br /&gt;變簡單很多吧! &lt;/li&gt;
&lt;li&gt;$.ajax在傳送陣列參數時，預設會改用ary[]=elem1&amp;amp;ary[]=elem2的Query String表示法(過去會轉成ary=elem1&amp;amp;ary=elem2)，這多半跟PHP、Ruby on Rails搭配使用。 如果想要保留原做法&lt;code&gt;，需另外設定jQuery.ajaxSettings.traditional = true;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;$.ajax可不指定dataType，由Response的ContentType決定: applcation/json時自動調為&amp;quot;json&amp;quot;，text/javascript或application/x=javascript時變成”script”，text/xml時視為&amp;quot;xml”。 &lt;/li&gt;
&lt;li&gt;$.ajax設定ifModified:true時，支援&lt;a href="http://kui.name/blog/2009/etag%E5%92%8Cexpires%E5%8E%9F%E4%BE%86%E5%92%8C%E8%A8%AD%E5%AE%9A.html"&gt;ETag檢查&lt;/a&gt;決定是否使用Cache的內容。 &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;JSON解析原本都是用eval，從1.4起會&lt;a href="http://en.wikipedia.org/wiki/JSON#Native_JSON"&gt;在Browser有支援&lt;/a&gt;的情況下使用內建的JSON Parser(如: &lt;a href="http://blogs.msdn.com/ie/archive/2008/09/10/native-json-in-ie8.aspx"&gt;IE8&lt;/a&gt;, &lt;a href="http://blog.mozilla.com/webdev/2009/02/12/native-json-in-firefox-31/"&gt;FF3.1&lt;/a&gt;, Chrome, Safari)，比eval來得安全也更有效率。 &lt;/li&gt;
&lt;li&gt;.serialize支援HTML5的欄位元素，例如: datetime, range。 &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;$.ajax多了context參數，在Callback函數中可以透過this直接存取context所傳入的元素物件，不必再用&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/03/11/4346.aspx"&gt;Closure&lt;/a&gt;，簡單很多! 例如: &lt;br /&gt;&lt;font color="#00ff00"&gt;$.ajax({ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; url: “gettime.aspx”, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; context: $(“#spnNowTime”), &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; success: function(s) { context.html(s); } &lt;br /&gt;});&lt;/font&gt; &lt;/li&gt;
&lt;li&gt;$.get, $.post, $getJSON, $.getScript 的success Callback多了第三個傳入參數--XHR。以前若想存取XHR，就必須放棄$.get等簡易寫法，回頭改用$.ajax。 &lt;/li&gt;
&lt;li&gt;送出AJAX Request時不管有無資料內容，一律傳送Content-Type Header，以符合某些應用場合的要求。 &lt;/li&gt;
&lt;li&gt;可以指定JSONP的callback函數名稱了! 也就是在&lt;a href="http://msdn.microsoft.com/zh-tw/asp.net/dd722589.aspx"&gt;邊做邊學jQuery第14集&lt;/a&gt;中提到的jsonp1238089172708，現在可透過jsonpCallback參數自訂。 &lt;/li&gt;
&lt;li&gt;$.ajax用onreadystatechange取代setTimeout輪詢，改善效能 。&lt;/li&gt;
&lt;li&gt;.text()支援CDATA &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;很酷的新HTML元素建構寫法: &lt;br /&gt;&lt;font color="#00ff00"&gt;jQuery(&amp;quot;&amp;lt;div/&amp;gt;&amp;quot;, { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; id: &amp;quot;foo&amp;quot;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; css: { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; height: &amp;quot;50px&amp;quot;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; width: &amp;quot;50px&amp;quot;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; color: &amp;quot;blue&amp;quot;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; backgroundColor: &amp;quot;#ccc&amp;quot; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; click: function() { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $(this).css(&amp;quot;backgroundColor&amp;quot;, &amp;quot;red&amp;quot;); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;}).appendTo(&amp;quot;body&amp;quot;);&lt;/font&gt; &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;.eq(-N), .get(-N)可以取&amp;quot;倒數第N個&amp;quot;，.first(), .last()可以取第一個跟最後一個。 &lt;/li&gt;
&lt;li&gt;過去jQuery()會傳回document的jQuery物件，1.4版起則改為傳回空的jQuery集合，以便動態加入元素。jQuery().ready()在1.4仍維持jQuery(document).ready()的效果，但建議不要再用了。 &lt;/li&gt;
&lt;li&gt;jQuery(“tagName”)改用getElementByTagName，速度大幅改善；$(&amp;quot;&amp;lt;div&amp;gt;”), $(“&amp;lt;div /&amp;gt;”), $(“&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;”)均改用document.createElement，$(“&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;”)效能己改善。 &lt;/li&gt;
&lt;li&gt;.css()加快兩倍、.addClass(), removeClass(), .hasClass()加快三倍。 &lt;/li&gt;
&lt;li&gt;.toggleClass()支援一次切換多個class，例如: toggleClass(&amp;quot;class1 class2&amp;quot;)。 &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;.data(myCacheObject)可以用傳入的物件置換掉整個Cache物件，而.data()可以取回整個Cache物件。 &lt;/li&gt;
&lt;li&gt;.data()使用的Cache物件改成有用到才建立，以改善效能。 &lt;/li&gt;
&lt;li&gt;呈現動畫時，可針對不同屬性設定不同的Easing效果。[參考: 天才少年&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/06/30/jquery-this.aspx"&gt;James Padolsey&lt;/a&gt;的&lt;a href="http://james.padolsey.com/javascript/easing-in-jquery-1-4a2/"&gt;Demo&lt;/a&gt;] &lt;/li&gt;
&lt;li&gt;jQuery.proxy()可以為現有函數產生一個分身，並指定該分身的Scope(簡單來就是強制指定this)。這有什麼用呢? 常見的案例是在事件函數中，要用另一個元素當作this。例如: &lt;br /&gt;&lt;font color="#00ff00"&gt;var f = function() { alert(this.id); }; &lt;br /&gt;$(&amp;quot;#A,#B&amp;quot;).click(jQuery.proxy(f, $(&amp;quot;#A&amp;quot;)[0]));&lt;/font&gt; &lt;br /&gt;在A,B上掛了同一個click事件，但透過jQuery.proxy指定Scope為A，則B的click事件裡，this也會指向A。 &lt;/li&gt;
&lt;li&gt;.bind()時可傳入物件{ click: function() { … }, keydown: function() { … } }，一次指定多個事件。 &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;克服了change(), submit()在IE裡跟其他瀏覽器部分行為有差異的問題。 &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;新事件focusin, focusout。類似focus及blur，但是支援Bubble Up。應用範例，&amp;lt;p&amp;gt;中包了&amp;lt;input&amp;gt;，當&amp;lt;input&amp;gt;取得焦點時，&amp;lt;p&amp;gt;的focusin事件也會被觸發。 &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;除了ready, focus(可用focusin取代), blur(可用focusout取代)，所有的事件都可以.live()了，萬歲!!! 另外，live的對象也可以指定Context了。(這應該可以克服上回在&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/04/bind-to-iframe.aspx"&gt;滲透式live&lt;/a&gt;管不到Iframe document的問題) &lt;/li&gt;
&lt;li&gt;.ready()會使用setTimeout持續檢查document.body是否存在，原則上只用來解決Safari瀏覽器的少數問題案例。 &lt;/li&gt;
&lt;li&gt;非IE瀏覽器不再做unload事件的Memory Leak檢查以加快速度。 &lt;/li&gt;
&lt;li&gt;.append(), .prepend(), .before(), .after()變快約一倍，.html()變快三倍，.remove(), .empty()變快4倍。 &lt;/li&gt;
&lt;li&gt;新方法: .detach()，將元素自DOM移除，但保留事件函數，多半用在暫時移除，稍後加回去的情境。 &lt;/li&gt;
&lt;li&gt;新方法: .unwrap()，剝掉外層，留下html()的部分。例如: &amp;lt;div id=&amp;quot;X&amp;quot;&amp;gt;&amp;lt;span&amp;gt;A&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;，$(&amp;quot;#X&amp;quot;).unwrap() -&amp;gt; &amp;lt;span&amp;gt;A&amp;lt;/span&amp;gt; &lt;/li&gt;
&lt;li&gt;內部函數domManip加入Cache機制，jQuery(&amp;quot;&amp;lt;div&amp;gt;&amp;quot;), .after(&amp;quot;&amp;lt;div&amp;gt;&amp;quot;)會比以前快。 &lt;/li&gt;
&lt;li&gt;沒有加進DOM的物件也可以用.before(), .after(), .replaceWith()。例如: jQuery(&amp;quot;&amp;lt;div/&amp;gt;&amp;quot;).before(&amp;quot;&amp;lt;p&amp;gt;Hello&amp;lt;/p&amp;gt;&amp;quot;).appendTo(&amp;quot;body&amp;quot;) 。&lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;.clone(true)現在連.data()也一併會複製 。&lt;/li&gt;
&lt;li&gt;.offset()支援設定功能，可用來改變元素位置。(設定時，CSS position會被自動改成relative) &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;queue()不再只侷限在動畫應用上，新增.delay(n)函數，可暫停n ms、.next()可跳到下一個動作、clearQueue()可以清除動作。 &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;.index()取得元素在同層元素中的排行，.index(selector)取得元素在同層元素同符合selector的排行。 &lt;/li&gt;
&lt;li&gt;.has()。$(&amp;quot;div”).has(“a”) 相當於 $(&amp;quot;div:has(a)”) &lt;/li&gt;
&lt;li&gt;.nextUntil(), .prevUntil(), parentsUntil()，類似.nextAll(), .prevAll(), .parents()，但會一直向後/前/上蒐集元素，直到符合selector元素為止。 &lt;/li&gt;
&lt;li&gt;.add(), .closest()支援傳入第二個參數作為Context 。&lt;/li&gt;
&lt;li&gt;jQuery.isEmptyObject()用來判別是否物件沒有任何屬性 。&lt;/li&gt;
&lt;li&gt;jQuery.isPlainObject()用來判別是否為物件 。&lt;/li&gt;
&lt;li&gt;jQuery.contains(A, B)用來判別元素B是否被包在元素A中 。&lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;jQuery.noop()，什麼事都不做的空函數，用在一定要傳入函數作為參數的場合。 &lt;/li&gt;
&lt;li&gt;jQuery.unique()，只保留DOM元素陣列中不重複的部分，並依在DOM出現順序排列。 &lt;/li&gt;
&lt;li&gt;其他: jQuery.browser支援Engine導向，例如: jQuery.browser.webkit用來判別所有以WebKit開發的Browser、對Java Applet的支援更好、不再使用arguments.callee(ECMAScript 5要廢掉)、使用Closure Compiler而非YUI Min來壓縮jquery-1.4.min.js 。&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;&lt;font color="#ff8000"&gt;【改版後不相容之處】&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;改用1.4，請注意以下的寫法可能會出問題:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;.add()的結果改成依元素在DOM裡的順序排列 &lt;/li&gt;
&lt;li&gt;.clone(true)會一併複製事件跟.data()儲存的資料 &lt;/li&gt;
&lt;li&gt;jQuery.data(elem)不再只傳回id字串，而是該元素的.data() Cache物件 &lt;/li&gt;
&lt;li&gt;jQuery() != jQuery(document) &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;.val(“…”)作用在&amp;lt;option&amp;gt;或&amp;lt;input type=”checkbox”&amp;gt;時，只認value，不再看text &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;jQuery.browser.version現在傳回Engine版本 &lt;/li&gt;
&lt;li&gt;將會阻擋格式不符規定的JSON表示字串 &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;預設會以PHP/Rails的ary[]=elem1&amp;amp;ary[]=elem2方法序列化參數，如想維持ary=elem1&amp;amp;ary=elem2的做法，請設定jQuery.ajaxSettings.traditional = true; &lt;/li&gt;
&lt;li&gt;內建屬性jQuery.className移除 &lt;/li&gt;
&lt;li&gt;jQuery.extend(true, …)將不再適用於非物件及陣列 &lt;/li&gt;
&lt;li&gt;&lt;font color="#ff0000"&gt;*&lt;/font&gt;$.ajax未指定dataType，而Response.ContentType == “text/javascript”時，將會自動被當成Script執行，不再當成string處理&lt;/li&gt;
&lt;li&gt;$.ajax的ifModified會一併納入ETags決定是否使用Cache。 &lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;好消息是，如果你發現原來的js換了1.4有以上問題，懶得改程式又很想用1.4，只要加掛一個Plug-In就可以解決。 &lt;br /&gt;&lt;font color="#00ff00"&gt;&amp;lt;script src=&amp;quot;http://code.jquery.com/jquery.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt; &lt;br /&gt;&amp;lt;script src=&amp;quot;http://code.jquery.com/jquery.compat-1.3.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;我只能說，jQuery真是佛心來著呀!!&lt;/p&gt;
&lt;p&gt;&lt;font color="#ff8000"&gt;【註】&lt;/font&gt;&lt;font color="#ff0000"&gt;紅色*&lt;/font&gt;是我個人認為值得關注的改變&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5903" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Javascript/default.aspx">Javascript</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/jQuery/default.aspx">jQuery</category></item><item><title>連三拉三</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/13/mvp-2010.aspx</link><pubDate>Tue, 12 Jan 2010 15:26:20 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5886</guid><dc:creator>Jeffrey</dc:creator><slash:comments>11</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt;  &lt;p&gt;感謝各位鄉親支持，讓老人家再次獲得微軟肯定，第四度連莊MVP，今天收到Award Kit。&lt;/p&gt;  &lt;p&gt;附上很沒誠意的開箱照: (原本想安排正妹一起入鏡才符合當今開箱的主流時尚，無奈寒舍僅有的小正妹只顧著專心看海綿寶寶... 大家偶爾吃清淡一點也好)&lt;/p&gt;  &lt;p&gt;&lt;img src="http://blog.darkthread.net/photos/darkthread/images/5883/original.aspx" alt="" /&gt;&lt;/p&gt;  &lt;p&gt;從去年起，MVP禮品由傳統的阿宅玩具改成尊榮的&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/01/12/mvp-2009.aspx"&gt;水晶獎座&lt;/a&gt;。今年微軟又重新設計了一個水晶獎座，而旁邊可掛上砝碼形狀的年度環，未來連任時(如果還有機會的話)可以玩一下疊疊樂。&lt;/p&gt;  &lt;p&gt;今年的獎座挺美的，讓我想拿來當作商業攝影的練習題。盡管花了點功夫調光線、弄背景、也嘗試不同的曝光量，但照出來的作品還是未夠班呀~~ 大家湊和著看吧!&lt;/p&gt;  &lt;p&gt;&lt;img class="PopBoxImageSmall" src="http://blog.darkthread.net/photos/darkthread/images/5885/500x375.aspx" alt="" /&gt;&amp;#160;&amp;#160; &lt;img class="PopBoxImageSmall" src="http://blog.darkthread.net/photos/darkthread/images/5884/500x375.aspx" alt="" /&gt;&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5886" width="1" height="1"&gt;</description></item><item><title>BUG-VS2008在x64 OS下會忽略Form_OnLoad的未處理例外</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/12/vs2008-x64-unhandled-exception.aspx</link><pubDate>Mon, 11 Jan 2010 20:44:49 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5879</guid><dc:creator>Jeffrey</dc:creator><slash:comments>1</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;昨天河道上看到噗友&lt;a href="http://www.plurk.com/bauann"&gt;bauann&lt;/a&gt;為了VS2008在W7 x64下無法順利運作，重灌到滿頭大汗外加內心淌血。我原本以為這是一起&amp;quot;抽中籤王&amp;quot;的個案，因為我公司與家裡的環境分別是Win2008 x64 + VS2008與W7 x64 + VS2008，印象中都可以正常使用。(若公司機器的VS2008有問題還混到現在，應該早就被炒魷魚了 XD)&lt;/p&gt;  &lt;p&gt;不過，噗裡引用了一篇&lt;a href="http://social.msdn.microsoft.com/Forums/en-SG/vsdebug/thread/69a0b831-7782-4bd9-b910-25c85f18bceb"&gt;論壇討論&lt;/a&gt;，卻讓我想起一些東西...&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#ff8000"&gt;One &lt;strong&gt;VERY&lt;/strong&gt; important point is that this issue is only on exceptions raised during the Forms.OnLoad event handler (or methods called from within this event handling).&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;回憶起確實遇過Form_Load階段有錯誤，卻沒被VS2008抓到的經驗，當時很狐疑是否VS2008某個設定沒調好才會這個樣子，但因為不致&amp;quot;卡關&amp;quot;，便未深究。&lt;/p&gt;  &lt;p&gt;bauann提供的資訊解答了我的疑惑，我寫了一個WinForm Project來驗證:&lt;/p&gt;  &lt;div class="BlogCodeBlock"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Forms;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.IO;&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; WindowsFormsApplication1&lt;/pre&gt;

    &lt;pre&gt;{&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Form1 : Form&lt;/pre&gt;

    &lt;pre&gt;    {&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; InvalidPath =&lt;/pre&gt;

    &lt;pre&gt;            &lt;span class="str"&gt;&amp;quot;1:\\invlid_path.txt&amp;quot;&lt;/span&gt;;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; Form1()&lt;/pre&gt;

    &lt;pre class="alt"&gt;        {&lt;/pre&gt;

    &lt;pre&gt;            InitializeComponent();&lt;/pre&gt;

    &lt;pre class="alt"&gt;        }&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Form1_Load(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;

    &lt;pre&gt;        {&lt;/pre&gt;

    &lt;pre class="alt"&gt;            MessageBox.Show(&lt;span class="str"&gt;&amp;quot;Form1_Load 1&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; s = File.ReadAllText(InvalidPath);&lt;/pre&gt;

    &lt;pre class="alt"&gt;            MessageBox.Show(&lt;span class="str"&gt;&amp;quot;Form1_Load 2&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre&gt;        }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; button1_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;

    &lt;pre class="alt"&gt;        {&lt;/pre&gt;

    &lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; s = File.ReadAllText(InvalidPath);&lt;/pre&gt;

    &lt;pre class="alt"&gt;        }&lt;/pre&gt;

    &lt;pre&gt;    }&lt;/pre&gt;

    &lt;pre class="alt"&gt;}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;果不其然，MessageBox “Form1_Load 1”後，接著就進入WinForm操作界面。理論上在File.ReadAllText那一列就該因檔案路徑亂給而發生Exception，但在x64 OS下的VS2008卻若無其事地忽略之後的程式碼MessageBox.Show(“Form_Load 2”)繼續執行。在button1_Click裡，相同的程式碼，Unhandled Exception倒可以正確地被VS2008捕捉。&lt;/p&gt;

&lt;p&gt;由MSDN論壇的討論得知，這確認是&lt;a href="https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=357311#details"&gt;一個VS2008的Bug&lt;/a&gt;，目前尚無HotFix。但有幾種解決方法:&lt;/p&gt;

&lt;p&gt;1) 設定Exception throw時就攔截(如下圖)，但這會導致每一個try { … }遇到的Exception也觸發中斷。&lt;/p&gt;

&lt;p&gt;&lt;img class="PopBoxImageSmall" src="http://blog.darkthread.net/photos/darkthread/images/5878/500x375.aspx" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;2) 在Form_Load()第一列加入System.Diagnostics.Debugger.Break()，然後按Ctrl-F5跑程式(Start without Debugging)，如此Debugger會事後掛上去，就可攔到Unhandled Exception。&lt;/p&gt;

&lt;p&gt;以上兩個方法都不是頂好的根治之道，只能稍稍止痛，依目前的產品發展時程，我認為這個Bug被修復的機會不太大。但由於問題出現時機只限於Form_OnLoad事件，在使用Windows x64 + VS2008寫Windows Form Project時多加留意，I think I can live with it。&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5879" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/VS2008/default.aspx">VS2008</category></item><item><title>TIPS-保存Visual Studio偵錯時的Config修改結果</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/11/5877.aspx</link><pubDate>Mon, 11 Jan 2010 08:41:42 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5877</guid><dc:creator>Jeffrey</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;上回提過透過&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/12/03/set-config.aspx"&gt;程式修改config檔設定值&lt;/a&gt;，再分享一個私房小技巧。&lt;/p&gt; &lt;p&gt;當我們使用Visual Studio對程式偵錯時，VS在編譯(Build)時會一併將App.Config的內容覆寫到/debug/bin/yourAppName.exe.config及/debug/bin/&amp;#39;yourAppName.vshost.exe.Config。程式執行時，對config檔的修改其實是寫到yourAppName.vshost.exe.Config裡。當程式執行結束，yourAppName.vshost.exe.Config的內容會再被App.Config所覆蓋。換句話說，VS偵錯程式時對Config所做的修改會在程式結束後化為烏有，那還測個屁?? (這讓我一直聯想到月亮上那棵吳剛砍了幾千年還砍不斷的桂樹)&lt;/p&gt; &lt;p&gt;有些人建議改用自訂的config來保存設定值，但如此就無法借用現成方法更新設定，讓人有些不甘心。另一種做法是將bin目錄下的檔案Copy到其他目錄下再執行，但這又衍生出&amp;quot;部署&amp;quot;需求，破壞&amp;quot;改完程式按一下就馬上Debug&amp;quot;的流暢性。&lt;/p&gt; &lt;p&gt;於是我土法鍊鋼加入以下程式: 在程式結束時，先偵測是否為偵錯模式? 若是，則將Config檔案內容回寫App.Config，如此就不用再擔心程式修改結果被覆寫囉!&lt;/p&gt; &lt;div class="BlogCodeBlock"&gt; &lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Forms;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Configuration;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.IO;&lt;/pre&gt;&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; WF&lt;/pre&gt;&lt;pre class="alt"&gt;{&lt;/pre&gt;&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Form1 : Form&lt;/pre&gt;&lt;pre class="alt"&gt;    {&lt;/pre&gt;&lt;pre&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; Form1()&lt;/pre&gt;&lt;pre class="alt"&gt;        {&lt;/pre&gt;&lt;pre&gt;            InitializeComponent();&lt;/pre&gt;&lt;pre class="alt"&gt;        }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Form1_FormClosed(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, &lt;/pre&gt;&lt;pre&gt;            FormClosedEventArgs e)&lt;/pre&gt;&lt;pre class="alt"&gt;        {&lt;/pre&gt;&lt;pre&gt;            System.Configuration.Configuration conf =&lt;/pre&gt;&lt;pre class="alt"&gt;                ConfigurationManager.OpenExeConfiguration(&lt;/pre&gt;&lt;pre&gt;                    ConfigurationUserLevel.None);&lt;/pre&gt;&lt;pre class="alt"&gt;            conf.AppSettings.Settings[&lt;span class="str"&gt;&amp;quot;LastTime&amp;quot;&lt;/span&gt;].Value =&lt;/pre&gt;&lt;pre&gt;                DateTime.Now.ToString(&lt;span class="str"&gt;&amp;quot;HH:mm:ss&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;            conf.Save(ConfigurationSaveMode.Modified);&lt;/pre&gt;&lt;pre&gt;            &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;            {&lt;/pre&gt;&lt;pre&gt;                &lt;span class="rem"&gt;//Debug Mode時回寫app.config&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (System.Diagnostics.Debugger.IsAttached)&lt;/pre&gt;&lt;pre&gt;                    File.Copy(conf.FilePath,&lt;/pre&gt;&lt;pre class="alt"&gt;                    &lt;span class="str"&gt;&amp;quot;..\\..\\app.config&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)&lt;/pre&gt;&lt;pre&gt;            {&lt;/pre&gt;&lt;pre class="alt"&gt;                MessageBox.Show(ex.Message);&lt;/pre&gt;&lt;pre&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;        }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Form1_Load(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;&lt;pre&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;            System.Configuration.Configuration conf =&lt;/pre&gt;&lt;pre&gt;                ConfigurationManager.OpenExeConfiguration(&lt;/pre&gt;&lt;pre class="alt"&gt;                    ConfigurationUserLevel.None);&lt;/pre&gt;&lt;pre&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.Text = &lt;span class="str"&gt;&amp;quot;LastTime =&amp;gt; &amp;quot;&lt;/span&gt; + &lt;/pre&gt;&lt;pre class="alt"&gt;                conf.AppSettings.Settings[&lt;span class="str"&gt;&amp;quot;LastTime&amp;quot;&lt;/span&gt;].Value;&lt;/pre&gt;&lt;pre&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;    }&lt;/pre&gt;&lt;pre&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5877" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Tips/default.aspx">Tips</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/VS2005/default.aspx">VS2005</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/VS2008/default.aspx">VS2008</category></item><item><title>CODE-在SQL Server XQuery中使用欄位或變數值當條件</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/08/xquery-variable.aspx</link><pubDate>Fri, 08 Jan 2010 08:03:48 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5863</guid><dc:creator>Jeffrey</dc:creator><slash:comments>1</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;今天處理到一個需求，要在SQL 2005中用Table1 JOIN Table2，Table2中有個XML欄位，裡面有多筆資料，JOIN時要用Table1的某個欄位當條件在XML中挑出特定XmlNode。&lt;/p&gt; &lt;p&gt;聽起來很模糊對吧? 我用來實例來比喻，假設有個Player資料表跟Team資料表，Team資料表中有個MemberListXml欄位，其中有該球隊成員的相關資料。我今天要用Player資料表去JOIN Team資料表，先找出Player所屬球隊，再從該球隊MemberListXml中用XPath語法調出該名球員的資料。&lt;/p&gt; &lt;p&gt;&lt;a href="http://msdn.microsoft.com/zh-tw/library/ms190262.aspx"&gt;XQuery&lt;/a&gt;允許我們在SQL Server中使用熟悉的XPath，由於PlayerNo是變數，直覺上大家會想到動態組裝XPath字串，例如: query(&amp;#39;/Members/Player[@PlayerNo = &amp;quot;&amp;#39; + Player.PlayerNo + &amp;#39;&amp;quot;])，但此時SQL會潑你一盆冷水，告訴你query()只能接受預先寫死的字串!! 怎麼辦? &lt;/p&gt; &lt;p&gt;請看示範:&lt;/p&gt; &lt;div class="BlogCodeBlock"&gt; &lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @Team &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; (TeamNo &lt;span class="kwrd"&gt;INT&lt;/span&gt;, MemberListXml XML);&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @Player &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; (PlayerNo &lt;span class="kwrd"&gt;INT&lt;/span&gt;, TeamNo &lt;span class="kwrd"&gt;INT&lt;/span&gt;, PlayerName &lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(16));&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;INSERT&lt;/span&gt; &lt;span class="kwrd"&gt;INTO&lt;/span&gt; @Team &lt;span class="kwrd"&gt;VALUES&lt;/span&gt;(1, &lt;span class="str"&gt;&amp;#39;&amp;lt;Members&amp;gt;&lt;/pre&gt;&lt;pre&gt;&amp;lt;Player PlayerNo=&amp;quot;1&amp;quot; Score=&amp;quot;5&amp;quot; /&amp;gt;        &lt;/pre&gt;&lt;pre class="alt"&gt;&amp;lt;Player PlayerNo=&amp;quot;2&amp;quot; Rank=&amp;quot;4&amp;quot; /&amp;gt;&lt;/pre&gt;&lt;pre&gt;&amp;lt;Player PlayerNo=&amp;quot;3&amp;quot; Position=&amp;quot;Pitcher&amp;quot; /&amp;gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&amp;lt;/Members&amp;gt;&amp;#39;&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;INSERT&lt;/span&gt; &lt;span class="kwrd"&gt;INTO&lt;/span&gt; @Player &lt;span class="kwrd"&gt;VALUES&lt;/span&gt;(1, 1, &lt;span class="str"&gt;&amp;#39;Jeffrey&amp;#39;&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;INSERT&lt;/span&gt; &lt;span class="kwrd"&gt;INTO&lt;/span&gt; @Player &lt;span class="kwrd"&gt;VALUES&lt;/span&gt;(2, 1, &lt;span class="str"&gt;&amp;#39;Darkthread&amp;#39;&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;INSERT&lt;/span&gt; &lt;span class="kwrd"&gt;INTO&lt;/span&gt; @Player &lt;span class="kwrd"&gt;VALUES&lt;/span&gt;(3, 1, &lt;span class="str"&gt;&amp;#39;Wang&amp;#39;&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt rem"&gt;--如果要從Team.MemberListXml中挑出Player的資料應如何JOIN&lt;/pre&gt;&lt;pre class="rem"&gt;--直覺上會寫成&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; P.PlayerNo, P.PlayerName,&lt;/pre&gt;&lt;pre&gt;       T.MemberListXml.query(&lt;/pre&gt;&lt;pre class="alt"&gt;       &lt;span class="str"&gt;&amp;#39;/Members/Player[@PlayerNo = &amp;quot;&amp;#39;&lt;/span&gt; + P.PlayerNo + &lt;span class="str"&gt;&amp;#39;&amp;quot;]&amp;#39;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;       ) &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; @Player P &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; @Team T &lt;span class="kwrd"&gt;ON&lt;/span&gt; P.TeamNo = T.TeamNo&lt;/pre&gt;&lt;pre class="rem"&gt;--很不幸地，一執行就會得到以下錯誤&lt;/pre&gt;&lt;pre class="alt rem"&gt;--The argument 1 of the xml data type method &amp;quot;query&amp;quot; must be a string literal.&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt rem"&gt;--別怕!! 天無絕人之路，向&lt;a style="color:red;" href="http://msdn.microsoft.com/en-us/library/ms191214.aspx"&gt;sql:column(&amp;quot;ColName&amp;quot;)&lt;/a&gt;尋求救贖吧!&lt;/pre&gt;&lt;pre class="rem"&gt;--另外，還有姐妹品 &lt;a style="color:red;" href="http://msdn.microsoft.com/en-us/library/ms188254.aspx"&gt;sql:variable(&amp;quot;@varName&amp;quot;)&lt;/a&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; P.PlayerNo, P.PlayerName,&lt;/pre&gt;&lt;pre&gt;       T.MemberListXml.query(&lt;/pre&gt;&lt;pre class="alt"&gt;       &lt;span class="str"&gt;&amp;#39;/Members/Player[@PlayerNo = sql:column(&amp;quot;P.PlayerNo&amp;quot;)]&amp;#39;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;       ) &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; @Player P &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; @Team T &lt;span class="kwrd"&gt;ON&lt;/span&gt; P.TeamNo = T.TeamNo&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5863" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/SQL+2005/default.aspx">SQL 2005</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/SQL+2008/default.aspx">SQL 2008</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/CODE/default.aspx">CODE</category></item><item><title>CODE-用FtpWebRequest搬移FTP Server上的檔案</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/08/move-ftp-file.aspx</link><pubDate>Fri, 08 Jan 2010 05:39:02 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5860</guid><dc:creator>Jeffrey</dc:creator><slash:comments>5</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;寫程式這麼多年，第一次遇到要在FTP Server搬檔案的需求，特此PO文一篇留念。&lt;/p&gt; &lt;p&gt;原本很擔心&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2007/06/23/tips-write-a-resumable-ftp-download-with-net-2-0.aspx"&gt;我大戰FTP的得力助手--FtpWebRequest&lt;/a&gt;不支援這個較少見的需求，看了一下&lt;a href="http://msdn.microsoft.com/en-us/library/system.net.webrequestmethods.ftp_members.aspx"&gt;WebRequestMethods.Ftp&lt;/a&gt;，還真沒看到Move、MoveFolder之類的項目。且慢，原來這裡有一個隱藏密技，&lt;a href="http://msdn.microsoft.com/en-us/library/system.net.webrequestmethods.ftp.rename.aspx"&gt;Rename&lt;/a&gt;時把目錄也換掉，就可達到搬檔案的效果了。程式範例如下，請笑納。&lt;/p&gt; &lt;div class="BlogCodeBlock"&gt; &lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;&lt;pre&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; url = &lt;span class="str"&gt;&amp;quot;ftp://192.168.1.1/origFolder/origFile.txt&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;    FtpWebRequest req = FtpWebRequest.Create(url) &lt;span class="kwrd"&gt;as&lt;/span&gt; FtpWebRequest;&lt;/pre&gt;&lt;pre class="alt"&gt;    req.Credentials = &lt;span class="kwrd"&gt;new&lt;/span&gt; NetworkCredential(&lt;span class="str"&gt;&amp;quot;username&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;password&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;    req.Method = WebRequestMethods.Ftp.Rename;&lt;/pre&gt;&lt;pre class="alt"&gt;    req.RenameTo = &lt;span class="str"&gt;&amp;quot;/newFolder/newFileName.txt&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;    &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;    {&lt;/pre&gt;&lt;pre&gt;        &lt;span class="kwrd"&gt;using&lt;/span&gt; (StreamReader sr = &lt;/pre&gt;&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;new&lt;/span&gt; StreamReader(req.GetResponse().GetResponseStream()))&lt;/pre&gt;&lt;pre&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&amp;nbsp;&amp;nbsp; &lt;span class="rem"&gt;//測試發現，正常時傳回的是空字串，不用處理&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; result = sr.ReadToEnd();&lt;/pre&gt;&lt;pre class="alt"&gt;        }&lt;/pre&gt;&lt;pre&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)&lt;/pre&gt;&lt;pre&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;        &lt;span class="rem"&gt;//... 錯誤處理 ...&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5860" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/.NET/default.aspx">.NET</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/CODE/default.aspx">CODE</category></item><item><title>HttpUtility.ParseQueryString與雙頻式Request參數解析</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/06/parsequerystring.aspx</link><pubDate>Wed, 06 Jan 2010 08:23:00 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5855</guid><dc:creator>Jeffrey</dc:creator><slash:comments>2</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;手邊有個需求，要把IIS Log Query String裡的參數解析出來，例如: &lt;font color="#00ff00"&gt;&amp;quot;?a=LeftMenu&amp;amp;t=%u9ed1%u6697%u57f7%u884c%u7dd2&amp;amp;u=/Darkthread.aspx&amp;amp;_=1262748681109&amp;quot;&lt;/font&gt;。需求不難，但要拆解參數、UrlDecode，眉角還挺多的。原本已捲起袖子打算自己動手寫，頓時想到佛心的HttpUtility Class可能會內建，一找之下，果然發現了好東西&lt;a href="http://msdn.microsoft.com/en-us/library/ms150046.aspx"&gt;HttpUtility.ParseQueryString&lt;/a&gt;! &lt;/p&gt; &lt;p&gt;送字串進去就傳回NameValueCollection，連%u9ed1這些Uncode編碼也會一併解好，十分方便。&lt;/p&gt; &lt;div class="BlogCodeBlock"&gt; &lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;&lt;pre&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; query = &lt;/pre&gt;&lt;pre&gt;&lt;span class="str"&gt;&amp;quot;?a=LeftMenu&amp;amp;t=%u9ed1%u6697%u57f7%u884c%u7dd2&amp;amp;u=/Darkthread.aspx&amp;amp;_=1262748681109&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;    NameValueCollection nvc =&lt;/pre&gt;&lt;pre&gt;        HttpUtility.ParseQueryString(query);&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; key &lt;span class="kwrd"&gt;in&lt;/span&gt; nvc.Keys)&lt;/pre&gt;&lt;pre&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;        Console.WriteLine(&lt;span class="str"&gt;&amp;quot;{0} =&amp;gt; {1}&amp;quot;&lt;/span&gt;, key, nvc[key]);&lt;/pre&gt;&lt;pre&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;    Console.Read();&lt;/pre&gt;&lt;pre&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;執行結果:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;font color="#00ff00"&gt;a =&amp;gt; LeftMenu&lt;br /&gt;t =&amp;gt; 黑暗執行緒&lt;br /&gt;u =&amp;gt; /Darkthread.aspx&lt;br /&gt;_ =&amp;gt; 1262748681109&lt;/font&gt; &lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;看到這個方法，我想到前陣子網友三腳貓提了一個&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2008/07/16/querystring-encoding.aspx#5820"&gt;ASP串接ASP.NET的URL編碼問題&lt;/a&gt;，於是幫它想出一個新用途。我們都知道Query String編碼時有Encoding之分，例如: 黑暗執行緒用Big5編碼做UrlEncode會變成%b6%c2%b7t%b0%f5%a6%e6%ba%fc，此時用ASP.NET Request預設編碼(UTF-8)解析就會產生亂碼。
&lt;/p&gt;&lt;p&gt;雖然我們可以修改ASP.NET Request的Encoding設定或&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2008/07/16/querystring-encoding.aspx#5820"&gt;ASP檔的Encoding設定&lt;/a&gt;，若產生URL的一方無法配合更改，而我們又不想為了部分Request更動整個ASP.NET Request的編碼設定，我想到可以搞出類似以下的做法，不管傳入Unicode或BIG5版的UrlEncode，都可以正確解析: &lt;/p&gt;
&lt;div class="BlogCodeBlock"&gt;
&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&amp;lt;%@ Page Language=&lt;span class="str"&gt;&amp;quot;C#&amp;quot;&lt;/span&gt; %&amp;gt;&lt;/pre&gt;&lt;pre&gt;&amp;lt;script runat=&lt;span class="str"&gt;&amp;quot;server&amp;quot;&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Page_Load(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;&lt;pre&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; paramS = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (Request.Url.Query.Length &amp;gt; 0 &amp;amp;&amp;amp;&lt;/pre&gt;&lt;pre class="alt"&gt;        Regex.IsMatch(&lt;/pre&gt;&lt;pre&gt;            Request.RawUrl,&lt;/pre&gt;&lt;pre class="alt"&gt;            &lt;span class="rem"&gt;//利用以下特徵簡略(但草率)識別出BIG5 UrlEncode&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;            &lt;span class="str"&gt;&amp;quot;%[a-f][0-9a-f]&amp;quot;&lt;/span&gt;, RegexOptions.IgnoreCase)&lt;/pre&gt;&lt;pre class="alt"&gt;        )&lt;/pre&gt;&lt;pre&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;        NameValueCollection nvc =&lt;/pre&gt;&lt;pre&gt;            HttpUtility.ParseQueryString(&lt;/pre&gt;&lt;pre class="alt"&gt;            Request.RawUrl.Substring(Request.RawUrl.IndexOf(&lt;span class="str"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;) + 1),&lt;/pre&gt;&lt;pre&gt;            Encoding.GetEncoding(950));&lt;/pre&gt;&lt;pre class="alt"&gt;        paramS = nvc[&lt;span class="str"&gt;&amp;quot;s&amp;quot;&lt;/span&gt;];&lt;/pre&gt;&lt;pre&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;        paramS = Request[&lt;span class="str"&gt;&amp;quot;s&amp;quot;&lt;/span&gt;];&lt;/pre&gt;&lt;pre class="alt"&gt;    Response.Write(&lt;span class="str"&gt;&amp;quot;s=&amp;quot;&lt;/span&gt; + paramS);&lt;/pre&gt;&lt;pre&gt;    Response.End();&lt;/pre&gt;&lt;pre class="alt"&gt;}&lt;/pre&gt;&lt;pre&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;測試以下兩種URL，都可以正確解出&amp;quot;黑暗執行緒&amp;quot;，不知道這樣可不可以稱為&amp;quot;支援雙頻&amp;quot;? 呵呵呵...
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Default.aspx?s=%u9ed1%u6697%u57f7%u884c%u7dd2 
&lt;/li&gt;&lt;li&gt;Default.aspx?s=%b6%c2%b7t%b0%f5%a6%e6%ba%fc&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;font color="#ff8000"&gt; 【延伸閱讀】&lt;/font&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2008/07/16/querystring-encoding.aspx"&gt;【茶包射手專欄】QueryString的中文編碼問題&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2007/09/16/1083.aspx"&gt;中文編碼解析工具 Ver 1.3&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5855" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/_2D4E8765E87DBC78_/default.aspx">中文編碼</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>CODE-滲透式jQuery.live()</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/04/bind-to-iframe.aspx</link><pubDate>Mon, 04 Jan 2010 08:40:22 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5842</guid><dc:creator>Jeffrey</dc:creator><slash:comments>12</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt; &lt;p&gt;手上有個需求，要掌握網頁裡所有連結被點擊的狀況。&lt;/p&gt; &lt;p&gt;對jQuery來說這是小菜一碟，利用$(&amp;quot;a&amp;quot;).live(&amp;quot;click&amp;quot;, function() { ... });就可在使用者點擊連結時加入自訂邏輯。不過，有挑戰性的部分在於網頁中可能穿插IFrame內嵌其他網頁，原本這個手腳只想動在MasterPage，就打算一口氣將網站所有網頁一網打盡，但$(&amp;quot;a&amp;quot;)的範圍只限於jQuery所在的window物件範圍，如果連內嵌網頁都要涵蓋，感覺上得在內嵌網頁裡也加上jQuery，也跑一次$(&amp;quot;a&amp;quot;).live(&amp;quot;click&amp;quot;, ...)。&lt;/p&gt; &lt;p&gt;&amp;quot;要手動修改一大堆網頁&amp;quot;這件事徹底挑動了【懶人】最敏感的神經，逼我又動起歪腦筋--是否可以找出主網頁裡所有的內嵌網頁，再滲透進去一一加掛$(&amp;quot;a&amp;quot;).live(&amp;quot;click&amp;quot;, ...)? 理論上只要不違背&lt;a href="https://developer.mozilla.org/en/Same_origin_policy_for_JavaScript"&gt;Same Origin Policy&lt;/a&gt;，主網頁可以透過&lt;a href="http://msdn.microsoft.com/en-us/library/ms533692(VS.85).aspx"&gt;contentWindow屬性&lt;/a&gt;存取到內嵌網頁的DOM，技術上是可行的。&lt;/p&gt; &lt;p&gt;於是，我試出了以下的Prototype，在此野人現曝一番，歡迎大家回饋與指教。&lt;/p&gt; &lt;div class="BlogCodeBlock"&gt; &lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt; &lt;span class="attr"&gt;src&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;../js/jquery-1.3.2.js&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="rem"&gt;//用load而不是ready，會等所有IFrame都載入後才觸發&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;$(window).load(&lt;span class="kwrd"&gt;function&lt;/span&gt; () {&lt;/pre&gt;&lt;pre class="alt"&gt;    &lt;span class="rem"&gt;//將設定邏輯寫成function，稍後可再度利用&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; hookProc = &lt;span class="kwrd"&gt;function&lt;/span&gt; () {&lt;/pre&gt;&lt;pre class="alt"&gt;        $(&lt;span class="str"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;).live(&lt;span class="str"&gt;&amp;quot;click&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;function&lt;/span&gt; () {&lt;/pre&gt;&lt;pre&gt;            alert(&lt;span class="str"&gt;&amp;quot;clicked!&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;        });&lt;/pre&gt;&lt;pre&gt;    };&lt;/pre&gt;&lt;pre class="alt"&gt;    hookProc();&lt;/pre&gt;&lt;pre&gt;    &lt;span class="rem"&gt;//針對所有IFrame進行操作&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;    $(&lt;span class="str"&gt;&amp;quot;iframe&amp;quot;&lt;/span&gt;).each(&lt;span class="kwrd"&gt;function&lt;/span&gt; () {&lt;/pre&gt;&lt;pre&gt;        &lt;span class="rem"&gt;//透過IFrame.contentWindow存取其中的網頁&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;        &lt;span class="rem"&gt;//cross-domain時會失敗，故加上try&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; win, doc;&lt;/pre&gt;&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;try&lt;/span&gt; {&lt;/pre&gt;&lt;pre&gt;            win = &lt;span class="kwrd"&gt;this&lt;/span&gt;.contentWindow;&lt;/pre&gt;&lt;pre class="alt"&gt;            doc = win.document;&lt;/pre&gt;&lt;pre&gt;        } &lt;span class="kwrd"&gt;catch&lt;/span&gt;(err) {}&lt;/pre&gt;&lt;pre class="alt"&gt;        &lt;span class="rem"&gt;//無法取得IFrame的window或document就放棄&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!win || !doc) &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;        &lt;span class="rem"&gt;//檢查IFrame中是否已載入jQuery?&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!win.jQuery) {&lt;/pre&gt;&lt;pre class="alt"&gt;            &lt;span class="rem"&gt;//動態載入&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; jqInject = doc.createElement(&lt;span class="str"&gt;&amp;quot;script&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;            jqInject.src = &lt;span class="str"&gt;&amp;quot;../js/jquery-1.3.2.js&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;            jqInject.type = &lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;            doc.getElementsByTagName(&lt;span class="str"&gt;&amp;quot;head&amp;quot;&lt;/span&gt;)[0].appendChild(jqInject);&lt;/pre&gt;&lt;pre&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;        &lt;span class="rem"&gt;//等待jQuery載入&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;function&lt;/span&gt; waitjQueryLoaded() {&lt;/pre&gt;&lt;pre&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;typeof&lt;/span&gt; win.jQuery == &lt;span class="str"&gt;&amp;quot;undefined&amp;quot;&lt;/span&gt;) setTimeout(waitjQueryLoaded, 100);&lt;/pre&gt;&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt; {&lt;/pre&gt;&lt;pre&gt;                &lt;span class="rem"&gt;//將前述的邏輯對IFrame的window也做一次&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;                win.eval(&lt;span class="str"&gt;&amp;quot;(&amp;quot;&lt;/span&gt; + hookProc.toString() + &lt;span class="str"&gt;&amp;quot;)();&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;        }&lt;/pre&gt;&lt;pre&gt;        waitjQueryLoaded();&lt;/pre&gt;&lt;pre class="alt"&gt;    });&lt;/pre&gt;&lt;pre&gt;});&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Link in Parent&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;iframe&lt;/span&gt; &lt;span class="attr"&gt;src&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Child.htm&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;frm1&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;iframe&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;iframe&lt;/span&gt; &lt;span class="attr"&gt;src&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://www.google.com.tw&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;iframe&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;iframe&lt;/span&gt; &lt;span class="attr"&gt;src&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Child.htm&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Iframe1&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;iframe&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;PS: 以上的做法我想到兩個缺點(但對我的應用來說不是大問題) 1) $(window).load()可以確保所有IFrame都載入後才開始動作，相對地掛好事件前的空窗期會變長 2) 只支援單層結構，無法涵蓋IFrame裡又有IFrame的狀況。&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5842" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Javascript/default.aspx">Javascript</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/jQuery/default.aspx">jQuery</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/CODE/default.aspx">CODE</category></item><item><title>用.NET展現多核威力(2) - 一核一緒 王者之道?</title><link>http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/03/multicore-2.aspx</link><pubDate>Sat, 02 Jan 2010 22:39:00 GMT</pubDate><guid isPermaLink="false">d08a49d6-af59-4068-8b43-b7c037f78068:5838</guid><dc:creator>Jeffrey</dc:creator><slash:comments>6</slash:comments><description>&lt;span id="PostName"&gt;&lt;/span&gt;  &lt;p&gt;在&lt;a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2010/01/02/multicore-1.aspx"&gt;前一篇文章&lt;/a&gt;裡，我們陰了ThreadPool一下，把一個運算十分簡單，但是數量極其龐大的計算需求拆解成無數UserWorkItem交給ThreadPool執行，然後冷眼旁觀ThreadPool在lock機制的消磨下，慘敗給傻瓜都會的單一執行緒寫法，速度足足慢了七倍有餘...&lt;/p&gt;  &lt;p&gt;lock機制看來是最大的殺手。明明人手充足，卻規定所有人員必須排隊成一列輪流完成某個動作才能繼續工作，當完成工作本身所需的時間很短，則耗費在排隊的時間就顯得漫長而荒謬。這就是前一篇文章所點出的事實。&lt;/p&gt;  &lt;p&gt;那麼，在這個案例中，我們應如何改善? 概念很簡單---讓所有可用的CPU資源都專心投入在執行運算上，避免花費任何額外資源去處理不必要的工作(例如: lock機制)。&lt;/p&gt;  &lt;p&gt;第一步，先要除去心頭大患---lock機制!! 回到前文提到的50個阿宅組電腦的例子上(謎之聲: 上回尊稱&amp;quot;電腦組裝達人&amp;quot;，這回簡稱&amp;quot;阿宅&amp;quot;，夠現實!)，要求所有人排隊領組裝套件是為了確保所有的套件都有分配出去，並且每份套件只被交付給一個人。在我們的案例中，還有另一方免排隊的好方法: 先算好有多少份組件，有多少人，預先把誰處理哪幾件分配好。一開始就把各人應處理的組件發下去，就不必大家擠著排隊。而我們也不再需要再去關心還有多少組件沒有分完做完，改問每個人是否已做完所有分配到的工作即可，這麼一來也不必麻煩大家排隊到黑板上寫正字。&lt;/p&gt;  &lt;p&gt;對應到程式碼上，假設我們有一台四核的電腦，便可以把1000萬次(0 - 9,999,999)拆成0 - 2,499,999、2,500,000 - 4,999,999、5,000,000 - 7,499,999、7,500,000 - 9,999,999四組，建立四個執行緒執行，如此讓四核同時各跑250萬次運算，理論上總運算時間就可以大幅減少(理論值是1/4，但會有其他額外的Overhead，並不會真的變成1/4)。&lt;/p&gt;  &lt;p&gt;至於應該要拆幾條執行緒，因為CPU在切換多條執行緒時會有Context Switch的損耗，原則上設成一核一條執行緒，應可將損耗壓到最低，但事實是否如此，我們可以實驗看看。&lt;/p&gt;  &lt;p&gt;以下的程式是由前文的Log10演算改寫而來，分為前後兩段，前段直接用迴圈計算1-5000萬的Log10，後段則建立WORKER_COUNT條執行緒，平分5000萬次的運算。每次測試時會前後段會各執行三次，以避免實驗誤差。&lt;/p&gt;  &lt;div class="BlogCodeBlock"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Diagnostics;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Threading;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Threading.Tasks;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; MultiCore&lt;/pre&gt;

    &lt;pre class="alt"&gt;{&lt;/pre&gt;

    &lt;pre&gt;    &lt;span class="kwrd"&gt;class&lt;/span&gt; TestAnonymousMethod&lt;/pre&gt;

    &lt;pre class="alt"&gt;    {&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;

    &lt;pre class="alt"&gt;        {&lt;/pre&gt;

    &lt;pre&gt;            &lt;span class="rem"&gt;//做5000萬次&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;int&lt;/span&gt; MAX_COUNT = 5000 * 10000;&lt;/pre&gt;

    &lt;pre&gt;            Stopwatch sw = &lt;span class="kwrd"&gt;new&lt;/span&gt; Stopwatch();&lt;/pre&gt;

    &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; round = 0; round &amp;lt; 3; round++)&lt;/pre&gt;

    &lt;pre&gt;            {&lt;/pre&gt;

    &lt;pre class="alt"&gt;                sw.Reset();&lt;/pre&gt;

    &lt;pre&gt;                &lt;span class="rem"&gt;//Console.WriteLine(&amp;quot;LOOP: {0:N0} - {1:N0}&amp;quot;, 0, MAX_COUNT);&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                sw.Start();&lt;/pre&gt;

    &lt;pre&gt;                &lt;span class="rem"&gt;//直接計算&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; MAX_COUNT; i++)&lt;/pre&gt;

    &lt;pre&gt;                {&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    &lt;span class="kwrd"&gt;double&lt;/span&gt; d = Math.Log10(Convert.ToDouble(i));&lt;/pre&gt;

    &lt;pre&gt;                }&lt;/pre&gt;

    &lt;pre class="alt"&gt;                sw.Stop();&lt;/pre&gt;

    &lt;pre&gt;                Console.WriteLine(&lt;span class="str"&gt;&amp;quot;循序處理 = {0:N0}ms&amp;quot;&lt;/span&gt;,&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    sw.ElapsedMilliseconds);&lt;/pre&gt;

    &lt;pre&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                sw.Reset();&lt;/pre&gt;

    &lt;pre&gt;                sw.Start();&lt;/pre&gt;

    &lt;pre class="alt"&gt;                &lt;span class="rem"&gt;//控制Thread數&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;                &lt;span class="kwrd"&gt;int&lt;/span&gt; WORKER_COUNT = 4;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                Thread[] workers = &lt;span class="kwrd"&gt;new&lt;/span&gt; Thread[WORKER_COUNT];&lt;/pre&gt;

    &lt;pre&gt;                &lt;span class="kwrd"&gt;int&lt;/span&gt; jobsCountPerWorker = MAX_COUNT / WORKER_COUNT;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; WORKER_COUNT; i++)&lt;/pre&gt;

    &lt;pre&gt;                {&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    &lt;span class="rem"&gt;//將全部工作切成WORKER_COUNT份，&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;                    &lt;span class="rem"&gt;//分給WORKER_COUNT個Thread執行&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    &lt;span class="kwrd"&gt;int&lt;/span&gt; st = jobsCountPerWorker * i;&lt;/pre&gt;

    &lt;pre&gt;                    &lt;span class="kwrd"&gt;int&lt;/span&gt; ed = jobsCountPerWorker * (i + 1);&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (ed &amp;gt; MAX_COUNT) ed = MAX_COUNT;&lt;/pre&gt;

    &lt;pre&gt;                    workers[i] = &lt;span class="kwrd"&gt;new&lt;/span&gt; Thread(() =&amp;gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    {&lt;/pre&gt;

    &lt;pre&gt;                        &lt;span class="rem"&gt;//Console.WriteLine(&amp;quot;LOOP: {0:N0} - {1:N0}&amp;quot;, st, ed);&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; j = st; j &amp;lt; ed; j++)&lt;/pre&gt;

    &lt;pre&gt;                        {&lt;/pre&gt;

    &lt;pre class="alt"&gt;                            &lt;span class="kwrd"&gt;double&lt;/span&gt; d = Math.Log10(Convert.ToDouble(j));&lt;/pre&gt;

    &lt;pre&gt;                        }&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    });&lt;/pre&gt;

    &lt;pre&gt;                    workers[i].Start();&lt;/pre&gt;

    &lt;pre class="alt"&gt;                }&lt;/pre&gt;

    &lt;pre&gt;                &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; WORKER_COUNT; i++)&lt;/pre&gt;

    &lt;pre class="alt"&gt;                    workers[i].Join();&lt;/pre&gt;

    &lt;pre&gt;                sw.Stop();&lt;/pre&gt;

    &lt;pre class="alt"&gt;                Console.WriteLine(&lt;span class="str"&gt;&amp;quot;平行處理[{1}] = {0:N0}ms&amp;quot;&lt;/span&gt;,&lt;/pre&gt;

    &lt;pre&gt;                    sw.ElapsedMilliseconds, WORKER_COUNT);&lt;/pre&gt;

    &lt;pre class="alt"&gt;            }&lt;/pre&gt;

    &lt;pre&gt;            Console.Read();&lt;/pre&gt;

    &lt;pre class="alt"&gt;        }&lt;/pre&gt;

    &lt;pre&gt;    }&lt;/pre&gt;

    &lt;pre class="alt"&gt;}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;測試結果為: (測試環境為Windows 7 Hyper VM on Windows 2008 R2，VM啟用了四個CPU)&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;循序處理 = 2,750ms 
    &lt;br /&gt;平行處理[4] = 1,006ms 

    &lt;br /&gt;循序處理 = 2,762ms 

    &lt;br /&gt;平行處理[4] = 1,121ms 

    &lt;br /&gt;循序處理 = 2,764ms 

    &lt;br /&gt;平行處理[4] = 1,409ms&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;執行時間縮短為1/2到1/3左右。(數字不知是否受&amp;quot;VM模擬的4 CPU環境&amp;quot;影響，或許在實體機器上效益會更明顯)&lt;/p&gt;

&lt;p&gt;接著我們修改程式，讓WORKER_COUNT由1-16，跑十次取平均時間，程式與結果以下:&lt;/p&gt;

&lt;div class="BlogCodeBlock"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;//做5000萬次&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;int&lt;/span&gt; MAX_COUNT = 5000 * 10000;&lt;/pre&gt;

    &lt;pre class="alt"&gt;Stopwatch sw = &lt;span class="kwrd"&gt;new&lt;/span&gt; Stopwatch();&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; WORKER_COUNT = 1; WORKER_COUNT &amp;lt; 16; WORKER_COUNT++)&lt;/pre&gt;

    &lt;pre class="alt"&gt;{=&lt;/pre&gt;

    &lt;pre&gt;    &lt;span class="kwrd"&gt;long&lt;/span&gt; sum = 0;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; round = 0; round &amp;lt; 50; round++)&lt;/pre&gt;

    &lt;pre&gt;    {&lt;/pre&gt;

    &lt;pre class="alt"&gt;        sw.Reset();&lt;/pre&gt;

    &lt;pre&gt;        sw.Start();&lt;/pre&gt;

    &lt;pre class="alt"&gt;        Thread[] workers = &lt;span class="kwrd"&gt;new&lt;/span&gt; Thread[WORKER_COUNT];&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="kwrd"&gt;int&lt;/span&gt; jobsCountPerWorker = MAX_COUNT / WORKER_COUNT;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; WORKER_COUNT; i++)&lt;/pre&gt;

    &lt;pre&gt;        {&lt;/pre&gt;

    &lt;pre class="alt"&gt;            &lt;span class="rem"&gt;//...省略...&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;            workers[i].Start();&lt;/pre&gt;

    &lt;pre class="alt"&gt;        }&lt;/pre&gt;

    &lt;pre&gt;        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; WORKER_COUNT; i++)&lt;/pre&gt;

    &lt;pre class="alt"&gt;            workers[i].Join();&lt;/pre&gt;

    &lt;pre&gt;        sw.Stop();&lt;/pre&gt;

    &lt;pre class="alt"&gt;        sum += sw.ElapsedMilliseconds;&lt;/pre&gt;

    &lt;pre&gt;    }&lt;/pre&gt;

    &lt;pre class="alt"&gt;    Console.WriteLine(&lt;span class="str"&gt;&amp;quot;平行處理[{1}] = {0:N0}ms&amp;quot;&lt;/span&gt;,&lt;/pre&gt;

    &lt;pre&gt;        sum / 50, WORKER_COUNT);&lt;/pre&gt;

    &lt;pre class="alt"&gt;}&lt;/pre&gt;

    &lt;pre&gt;Console.Read();&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;平行處理[1] = 3,253ms 
  &lt;br /&gt;平行處理[2] = 1,723ms 

  &lt;br /&gt;平行處理[3] = 1,316ms 

  &lt;br /&gt;&lt;font color="#ff0000"&gt;平行處理[4] = 1,155ms 
    &lt;br /&gt;&lt;/font&gt;平行處理[5] = 1,459ms 

  &lt;br /&gt;平行處理[6] = 1,448ms 

  &lt;br /&gt;平行處理[7] = 1,466ms 

  &lt;br /&gt;平行處理[8] = 1,517ms 

  &lt;br /&gt;平行處理[9] = 1,587ms 

  &lt;br /&gt;平行處理[10] = 1,633ms 

  &lt;br /&gt;平行處理[11] = 1,642ms 

  &lt;br /&gt;平行處理[12] = 1,735ms 

  &lt;br /&gt;平行處理[13] = 1,716ms 

  &lt;br /&gt;平行處理[14] = 1,759ms 

  &lt;br /&gt;平行處理[15] = 1,810ms 

  &lt;br /&gt;平行處理[16] = 1,863ms&lt;/p&gt;

&lt;p&gt;測試數據證明了我們的假設--&lt;font color="#ff8000"&gt;&lt;strike&gt;針對以運算為主的大量作業&lt;/strike&gt;在這個以簡單運算為主的大量作業案例中，Thread數與CPU數目相同時可獲得最佳執行效率&lt;/font&gt;。&lt;/p&gt;

&lt;p&gt;在接下來的文章裡，我們要來看看CLR 4.0幹了什麼好事?&lt;/p&gt;&lt;img src="http://blog.darkthread.net/aggbug.aspx?PostID=5838" width="1" height="1"&gt;</description><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/.NET/default.aspx">.NET</category><category domain="http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/Performance/default.aspx">Performance</category></item></channel></rss>