tag:blogger.com,1999:blog-75780395594717491692024-03-14T05:37:31.995+08:00Life OnlineCircle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.comBlogger215125tag:blogger.com,1999:blog-7578039559471749169.post-45648661111813674212020-11-26T15:40:00.006+08:002020-11-26T15:42:00.999+08:00【C#】XDocument Descendants() 取不到東西<pre class="prettyprint linenums:1"> string xml = @"<?xml version='1.0' encoding='utf-8'?>
<ComputerBuildReportRequest xmlns:i='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://schemas.ms.it.oem/digitaldistribution/2010/10'>
<Bindings>
<Binding>
<ProductKeyID>1000000002</ProductKeyID>
<HardwareHash>xxx</HardwareHash>
<HXSpecifics>
<UnitPartNumber>123456-789</UnitPartNumber>
</HXSpecifics>
</Binding>
<Binding>
<ProductKeyID>1000000003</ProductKeyID>
<HardwareHash>yyy</HardwareHash>
<HXSpecifics>
<UnitPartNumber>123456-787</UnitPartNumber>
</HXSpecifics>
</Binding>
</Bindings>
</ComputerBuildReportRequest>";
XDocument doc = XDocument.Parse(xml);
var elements = doc.Descendants("Binding"); // empty
</pre>
以前就碰過,一直懶得研究 XDocument 到底為什麼有時候會秀逗,直接改用 XmlDocument。
這次碰到非用不可的情況,就藉機深究下。 <div><br />
<a name='more'></a>
<br />
簡單說,有 namespace 的情況下查都要補 namespace 給它,非常智障。
<pre class="prettyprint linenums:1">string xml = @"<?xml version='1.0' encoding='utf-8'?>
<ComputerBuildReportRequest xmlns:i='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://schemas.ms.it.oem/digitaldistribution/2010/10'>
<Bindings>
<Binding>
<ProductKeyID>1000000002</ProductKeyID>
<HardwareHash>xxx</HardwareHash>
<HXSpecifics>
<UnitPartNumber>123456-789</UnitPartNumber>
</HXSpecifics>
</Binding>
<Binding>
<ProductKeyID>1000000003</ProductKeyID>
<HardwareHash>yyy</HardwareHash>
<HXSpecifics>
<UnitPartNumber>123456-787</UnitPartNumber>
</HXSpecifics>
</Binding>
</Bindings>
</ComputerBuildReportRequest>";
XDocument doc = XDocument.Parse(xml);
XNamespace df = doc.Root.Name.Namespace;
var elements = doc.Descendants(df + "Binding");
</pre>
而且這用法還不接受$串字的語法糖,是真的棒。 <div> ref: <a href="https://stackoverflow.com/questions/7503276/xml-linq-descendants-returns-nothing">https://stackoverflow.com/questions/7503276/xml-linq-descendants-returns-nothing</a></div></div>Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-18516630080256968832020-06-27T21:37:00.001+08:002020-06-27T21:37:25.933+08:00【C#】Verify permission of specific directoryActual verification of read permission to specific directory without opens a stream.<br />
<br />
<a name='more'></a>
<pre class="prettyprint linenums:1">private static bool HasPermissionToReadFiles(string path)
{
var readAllow = false;
var readDeny = false;
var firstFoundFile = Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories).FirstOrDefault();
if (firstFoundFile == null)
{
throw new Exception("There is no file in provided path.");
}
var accessControlList = Directory.GetAccessControl(firstFoundFile);
if (accessControlList == null)
return false;
var accessRules = accessControlList.GetAccessRules(true, true, typeof(SecurityIdentifier));
if (accessRules == null)
return false;
foreach (FileSystemAccessRule rule in accessRules)
{
if ((FileSystemRights.Read & rule.FileSystemRights) != FileSystemRights.Read) continue;
if (rule.AccessControlType == AccessControlType.Allow)
readAllow = true;
else if (rule.AccessControlType == AccessControlType.Deny)
readDeny = true;
}
return readAllow && !readDeny;
}
</pre>
<br />
<br />Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-84357036126941033042020-06-26T20:28:00.003+08:002020-06-27T21:31:27.801+08:00【Powershell】Create task scheduler entry用 PowerShell 建 scheduler task<br />
<br />
<a name='more'></a>CreateSSLCertificateSwitchSchedule.ps1<br />
<pre class="prettyprint linenums:1">$trigger = @(
$(New-ScheduledTaskTrigger -AtStartup -RandomDelay (New-TimeSpan -Minutes 2)),
$(New-ScheduledTaskTrigger -Daily -At 3am))
$action = New-ScheduledTaskAction -Execute "D:\bin\SwitchSSLCertificateBack\SwitchSSLCertificateBack.exe"
Register-ScheduledTask -TaskName "SwitchSSLCertificateBack" -Trigger $trigger -User "SYSTEM" -Action $action
</pre>
<br />
Trigger 有每天凌晨3點跟開機後兩分鐘兩種。<br />
<br />
CreateSSLCertificateSwitchSchedule.bat,主要是第三列的 ps call<br />
<pre class="prettyprint linenums:1">
cd /d "%~dp0<br />
Robocopy "." "D:\bin\SwitchSSLCertificateBack"<br />
Powershell.exe -executionpolicy remotesigned -File CreateSSLCertificateSwitchSchedule.ps1<br />
@echo off<br />
echo The batch has been finished. Press any key to exit.<br />
pause >nul
</pre>Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-6629577755623527242019-05-28T17:09:00.001+08:002019-05-28T17:09:46.936+08:00【MS-SQL】Can't open .trc file generated by SQLDiag想直接雙擊打開 SQLDiag 錄的 trc 但會碰到<br />
<div>
<br />
<div>
<div>
<span style="background-color: #f4cccc;">SQL Server Profiler</span></div>
<div>
<span style="background-color: #f4cccc;">Failed to open a file. Access is denied.</span></div>
的錯誤視窗<br />
<br />
<a name='more'></a>似乎是因為 SQL Server Service 用 NT 帳號跑起來它做出來的檔案不會繼承權限(尤其你是 domain account 進電腦沒有本機 admin)。<br />
<br />
trc 檔右鍵<br />
Properties > Security > Advanced > Permissions > Continue > Enable inheritance > OK<br />
再跑就可以了。<br />
<br />
ref: <a href="https://social.msdn.microsoft.com/Forums/sqlserver/en-US/4d51dd01-d0d0-4adb-a51e-2f7fa84be1d1/cant-open-trace-files?forum=databasedesign">MSDN</a></div>
</div>
Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-11980162418595858692019-05-28T16:03:00.000+08:002019-05-28T16:04:39.753+08:00【MS-SQL】SQLDiag debug要跑 SQLDiag 的時候發生錯誤,錄完之後沒產生 trc 檔,cmd 有以下錯誤。<br />
<span style="background-color: #f4cccc;"><machinename>\<instancename> Error querying installation path for SQLDIAG on <instancename> . Function result: 2. Message: The system cannot find the file specified.</instancename></instancename></machinename></span><br />
<br />
<a name='more'></a>但這看不出 file specified 指什麼,這時候要先找到執行目錄下的<br />
\internal\##MachineName_InstanceName_Run_sp_trace.OUT<br />
裡面才會有錯誤的細節。<br />
<span style="background-color: #f4cccc;">Msg 19062, Level 16, State 1, Server MachineName\InstanceName, Procedure sp_trace_create, Line 1</span><br />
<span style="background-color: #f4cccc;">Could not create a trace file.</span><br />
<span style="background-color: #f4cccc;">No active traces.</span><br />
<span style="background-color: #f4cccc;">Output folder=C:\Program Files\Microsoft SQL Server\MSRS11.SQL12\Reporting Services\LOG</span><br />
<span style="background-color: #f4cccc;">Windows error occurred while running SP_TRACE_CREATE. Error = 0x80070003(The system cannot find the path specified.).</span><br />
<br />
會發現目錄下缺了 LOG 這個資料夾(倒是有個叫 LogFiles,感覺就是寫的人沒溝通好),所以手動補上這個資料夾即可。<br />
<br />
ref: 恆逸的講師<br />
<br />Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-45642743392719919592019-05-21T14:47:00.002+08:002019-05-21T14:47:38.474+08:00【WCF】500 InternalServerError The server encountered an error processing the request. See server logs for more details<div class="heading1">
<span style="background-color: #f4cccc;"><b>Error Status Code:</b> 'InternalServerError'</span></div>
<span style="background-color: #f4cccc;"><b>Details: </b>The server encountered an error processing the request.
Please see the server logs for more details.</span><br />
<br />
但 Visual Studio 沒有拋出任何 exception。
<br />
<a name='more'></a><br />
在 Service class 加以下 attribute<br />
<pre class="prettyprint linenums:1">[ServiceBehavior(IncludeExceptionDetailInFaults = true)]</pre>
※ 注意是加在 class,不是 method。<br />
<br />
再用 fiddler 的 web view 就可以看到被隱藏的錯誤訊息了(通常是參數序列化轉換的問題)。<br />
<br />
ref: <a href="https://stackoverflow.com/questions/21803522/the-server-encountered-an-error-processing-the-request-see-server-logs-for-more">SO</a><br />
<br />Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-75145257065993274772019-01-08T17:29:00.001+08:002019-01-08T17:29:43.104+08:00【Visual Studio】Unexpected exception Could not load file or assembly '' or one of its dependencies. <span style="background-color: #f4cccc;">Unexpected exception Could not load file or assembly '' or one of its dependencies. </span><br />
<br />
<a name='more'></a>主程式 compile 的 platform 跟 dll 不一致,如果 dll 選 x64 主程式也要相同,不能選 Any CPU。Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-58911588907781359422018-12-19T16:31:00.005+08:002018-12-19T16:31:45.720+08:00【C#】Max concurrent tasks<a name='more'></a><pre class="prettyprint linenums:1">static void Main()
{
Foo();
Console.ReadLine();
}
private static async Task Foo()
{
var urls = new[] {
"A",
"B",
"C",
"D",
"E",
};
var maxThreads = 4;
var q = new ConcurrentQueue<string>(urls);
var tasks = new List<Task>();
for (int n = 0; n < maxThreads; n++)
{
tasks.Add(Task.Run(async () =>
{
while (q.TryDequeue(out string url))
{
Console.WriteLine($"start {url}");
await Task.Delay(3000);
Console.WriteLine($"end {url}");
}
}));
}
await Task.WhenAll(tasks);
}
</pre>
ref: <a href="https://markheath.net/post/constraining-concurrent-threads-csharp">sound code</a>Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-41693611553421616142018-11-26T18:43:00.000+08:002018-11-26T18:43:40.933+08:00【MS-SQL】Cannot open backup device 'xxx'. Operating system error 5(Access is denied.)<span style="background-color: #f4cccc;">Cannot open backup device 'E:\folder-name\file-name.bak'. Operating system error 5(Access is denied.).</span><br />
<br />
<a name='more'></a>SQL Server Service 沒有寫目的地資料夾的權限,補上即可Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-72069214721127326812018-11-24T17:24:00.000+08:002018-11-24T20:06:41.173+08:00【MS-SQL】Connection pool<span style="background-color: #f4cccc;">Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.</span><br /><br />
<a name='more'></a>Connection pool<br />
當一個方法用完了特定的 connection 時,其實它不會立刻被回收,而是會被放進 connection pool 保存。<br />
<br />
每個應用可以創造複數的 connection pools,取用哪個 pool 取決於 connection string 是否相同,這也是最好把 connection string 存在 config 中共用的理由之一。<br />
<br />
Connection pool 預設最多可以有 100 條 connection 存在,若是多緒共用相同的 pool,做的很慢沒有及時關閉 connection,pool 占滿,同 connection string 的其他命令等到超時就會出現開版的錯誤。<br />
<br />
根除這個問題應該要檢討業務邏輯的設定為什麼會造成額滿,是不是有關閉寫錯。<br />
<br />
若真的需求特殊可以調整 connection string 的 Max pool size 和 Min pool size 應對。<br />
<br />
Max pool size<br />
調整 pool 最多可容納的 connection 數量,預設為 100。<br />
<br />
Min pool size<br />
調整 pool 初始化時先幫你建好的 connection 數量,預設為 0。<br />
<br />
ref: <a href="https://www.huanlintalk.com/2012/05/net-connection-pool.html">蔡老師的文章</a>Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-51130820187728246272018-11-15T18:35:00.004+08:002018-11-15T18:37:09.037+08:00【MS-SQL】BACKUP LOG cannot be performed because there is no current database backup<span style="background-color: #f4cccc;">BACKUP LOG cannot be performed because there is no current database backup</span><br />
<br />
不確定是 shrink 還是改 log size 或其他什麼的,突然沒辦法用之前做的 full back 還原。<br />
<br />
<a name='more'></a><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-eVKb3JgOmiE/W-1LrYyN_3I/AAAAAAAAF3M/Gh6A_vK_TZEjX3qwQobq-dH1zbuy1TRMQCKgBGAs/s1600/de.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="736" data-original-width="1333" height="352" src="https://1.bp.blogspot.com/-eVKb3JgOmiE/W-1LrYyN_3I/AAAAAAAAF3M/Gh6A_vK_TZEjX3qwQobq-dH1zbuy1TRMQCKgBGAs/s640/de.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
ref: <a href="https://stackoverflow.com/a/29497004/1973651">SO</a>Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-20251920212358170852018-11-15T15:05:00.001+08:002018-11-15T18:36:58.034+08:00【MS-SQL】The transaction log for database 'DatabaseName' is full due to 'LOG_BACKUP'<span style="background-color: #f4cccc;">The transaction log for database 'DatabaseName' is full due to 'LOG_BACKUP'</span><br />
<br />
<a name='more'></a>交易紀錄爆炸,shrink 或增加上限。
<br />
<br />
Shrink
<br />
<pre class="prettyprint linenums:1">USE <DatabaseName>;
GO
-- Truncate the log by changing the database recovery model to SIMPLE.
ALTER DATABASE <DatabaseName>
SET RECOVERY SIMPLE;
GO
-- Shrink the truncated log file to 1 MB.
DBCC SHRINKFILE (<DatabaseName>_Log, 1);
GO
-- Reset the database recovery model.
ALTER DATABASE <DatabaseName>
SET RECOVERY FULL;
GO
</pre>
<br />
上限
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/--5s9OqOkgqI/W-1MEzcYezI/AAAAAAAAF3U/aS1iLE1EGx0uUpIHA1Sb45Kv3pHIzfaqACKgBGAs/s1600/demopng.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="499" data-original-width="826" height="386" src="https://4.bp.blogspot.com/--5s9OqOkgqI/W-1MEzcYezI/AAAAAAAAF3U/aS1iLE1EGx0uUpIHA1Sb45Kv3pHIzfaqACKgBGAs/s640/demopng.png" width="640" /></a></div>
<br />Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-89825973705408111682018-11-07T16:23:00.003+08:002018-11-07T17:13:35.031+08:00【C#】0x string to byte[] and convert backMD5 測試用到的<br />
<br />
<a name='more'></a><pre class="prettyprint linenums:1">public static byte[] HexStrToByteArray(string hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
public static string ByteArrayToHexStr(byte[] data)
{
if (data == null)
return string.Empty;
if (data.Length == 0)
return string.Empty;
StringBuilder dataStr = new StringBuilder();
dataStr.Append("0x");
foreach (byte b in data)
dataStr.Append(b.ToString("X2"));
return dataStr.ToString();
}
</pre>
ref: <a href="https://stackoverflow.com/questions/321370/how-can-i-convert-a-hex-string-to-a-byte-array">to byte array</a>, <a href="https://stackoverflow.com/questions/311165/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-and-vice-versa">to hex string</a>, <a href="https://stackoverflow.com/questions/68677/how-can-i-print-a-binary-value-as-hex-in-tsql">binary to hex string in TSQL</a>Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-46850091704734128052018-09-09T17:39:00.003+08:002018-09-09T17:39:43.648+08:00【C#】IProgressIProgress 是類似輕量化版的 BackgroundWorker<br />
<br />
<a name='more'></a>它沒有 IsBusy, WorkComplete 事件等,要自己做,但我覺得比較直觀,貌似對 async 的支援也好點。<br />
<pre class="prettyprint linenums:1">public partial class Form1 : Form
{
IProgress<int> _progress;
public Form1()
{
InitializeComponent();
_progress = new Progress<int>(UpdateProgressBar);
}
private void UpdateProgressBar(int val)
{
pbProgress.Value = val;
if (val == 100)
{
MessageBox.Show("Finished");
pbProgress.Value = 0;
}
}
private async void btnStart_Click(object sender, EventArgs e)
{
if (pbProgress.Value == 0)
{
await Task.Run(async () =>
{
for (int i = 0; i < 100; i++)
{
_progress.Report(i + 1);
await Task.Delay(100 - i);
}
});
}
}
}
</pre>
<br />
ref: <a href="https://github.com/iamshiao/MyProgressLab.git">GitHub 範例</a>(Form2是 backgroundworker,可以在 program 切換)<br />
<br />Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-32481241524858788782018-08-20T17:34:00.000+08:002018-08-20T17:38:52.641+08:00【C#】Various kinds of lock除了標準的 lock (){} 外,還有對應不同應用的其他鎖<br />
<br />
<a name='more'></a>根據同時是否允許複數的執行緒存取 critical section 可分為 exclusive 和 shared 兩類<br />
<br />
Exclusive<br />
指一次只能有一個 thread 進入。<br />
lock=Monitor、Mutex、Other EventWaitHandle<br />
<br />
Shared<br />
一次可以有指定數量的 threads 進入。<br />
Semaphore、ReadWriteLock<br />
<br />
<b>lock and Monitor</b><br />
基本上 lock(){}就是
<br />
<pre class="prettyprint linenums:1">var temp = obj;
Monitor.Enter(temp);
try
{
body
}
finally
{
Monitor.Exit(temp);
}
</pre>
的語法糖,如果沒有要用 Monitor.TryEnter() 設 timeout 的話都用 lock{}就可以。<br />
<br />
<b>Mutex</b><br />
以下是用作鎖的例子並附上同屬 EventWaitHandle 的 AutoResetEvent 交互參考,基本上 Mutex 的主要用途是<b>跨 Processes 同步</b>,沒有此需求就不要用它浪費資源了。<br />
<pre class="prettyprint linenums:1">//static AutoResetEvent _ewh = new AutoResetEvent(true);
static Mutex _mut = new Mutex();
static bool _taken = false;
static void Main()
{
for (int i = 0; i < 5; i++)
{
Task.Run(async () =>
{
await Task.Delay(new Random().Next(100, 500));
Take();
});
}
Console.ReadLine();
}
private static void Take()
{
//_ewh.WaitOne();
_mut.WaitOne();
if (_taken)
{
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} attempt failed, resource was taken");
}
else
{
_taken = true;
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} took the resource");
}
//_ewh.Set();
_mut.ReleaseMutex();
}
</pre>
<br />
<b>Semaphore</b><br />
這個跟 ReadWriteLock 都有 Slim 版,Slim 版不能跨 Processes,但資源消耗較小,一般會用 Slim 版。 用法類似 WaitHandle,但建構式處可指定進入緒的數量。<br />
<pre class="prettyprint linenums:1">static SemaphoreSlim sphs = new SemaphoreSlim(3);
static BlockingCollection<string> resources = new BlockingCollection<string>() { "res1", "res2", "res3", "res4", "res5", "res6", "res7", "res8", "res9" };
static void Main()
{
var resCount = resources.Count;
for (int i = 0; i < resCount; i++)
{
Task.Run(async () =>
{
await Take();
});
}
Console.ReadLine();
}
private async static Task Take()
{
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} is waiting");
sphs.Wait();
if (resources.Any())
{
var res = resources.Take();
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} takes the {res}");
}
else
{
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} attempt failed, all resources was taken");
}
await Task.Delay(new Random().Next(500, 1000));
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} released");
sphs.Release();
}
</pre>
我一直覺得 WaitHandle 這個家族的用法語意很差,但不知道為什麼很多類都是參考這個風格做的,搞得多緒每次寫每次查。<br />
<br />
ref: <a href="http://arthurmvc.blogspot.com/2013/09/netlock.html">亞斯狼(鎖差別一覽表)</a><br />
<br />
<br />Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-36787754517781011852018-08-20T14:51:00.001+08:002018-08-20T14:51:46.463+08:00【C#】Interlocked為多重執行緒共用的變數提供不可部分完成的作業 (Atomic Operation)。<br />
<br />
<a name='more'></a>以上為 MSDN 的解釋,白話一點講,<b>透過 Interlocked 提供的方法操作變數是執行緒安全的。</b><div>
<br /></div>
<div>
這個類通常用在基礎型別,所以常見的操作就是 Increment(相當於++)、Decrement(相當於--)、Exchange(相當於賦值)。</div>
Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-76424776054080426952018-08-19T21:07:00.001+08:002018-11-02T10:12:34.234+08:00【C#】TaskTask 是抽象化後的緒操作類(from the thread pool)<br />
<br />
<a name='more'></a>它的優點有<br />
<ol>
<li>可以回傳值</li>
<li>搭配 async await 優化對 I/O bound 任務的行為</li>
<li>語意改善</li>
</ol>
<br />
<b>回傳值</b><br />
Thread 是沒有回傳值這回事的,要靠存取一個外部變數來達成類似的功能,但 Task 可以直接如以下操作<br />
<pre class="prettyprint linenums:1">static void Main(string[] args)
{
FooAsync();
Console.ReadLine();
}
private static async void FooAsync()
{
string msg = await Task.Run(() =>
{
return "msg from task";
});
Console.WriteLine(msg);
}
</pre>
<br />
<b>await an I/O bound task</b><br />
簡單來說 CPU bound 是消耗本機 CPU 與相關資源程度來決定運算效能的任務,相對的 I/O bound 是即使提升了上述資源供給也沒有直觀幫助的任務;比方 web service,其速度取決於 伺服器要多久才能吐回資料,無關你自身的運算資源。<br />
<br />
標記方法為 async 搭配對 I/O 任務 await 可以迴避掉等待 output 占用 thread 的情況<br />
<pre class="prettyprint linenums:1">static void Main(string[] args)
{
FooAsync();
Console.ReadLine();
}
private static async void FooAsync()
{
string msg = await GetJson("https://jsonplaceholder.typicode.com/todos");
Console.WriteLine(msg);
}
public static async Task<string> GetJson(string url)
{
var client = new HttpClient();
return await client.GetStringAsync(url);
}
</string></pre>
<br />Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-88803997555351384992018-08-19T20:23:00.001+08:002018-08-19T20:23:42.650+08:00【C#】Exception handling while multi-threading<a name='more'></a><pre class="prettyprint linenums:1">static void Main(string[] args)
{
try
{
Task.Run(() =>
{
throw new Exception("occurs in task");
});
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
</pre>
執行上述程式你會發現 cmd 沒寫 ex.Message,原因是 exception handling 是 per thread 的,也就是說<b>在外緒發生的 exception 主緒 catch 不到</b>。<br />
<br />
這有幾個解<br />
1. 把 try catch 改包在裡面(這個最簡單)<br />
<pre class="prettyprint linenums:1">static void Main(string[] args)
{
Task.Run(() =>
{
try
{
throw new Exception("occurs in task");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
});
Console.ReadLine();
}
</pre>
<br />
2. 靠 TaskStatus 判斷執行結果並挖掘其中的錯誤<br />
<pre class="prettyprint linenums:1">var t = Task.Run(() =>
{
throw new Exception("occurs in task");
})
.ContinueWith((result) =>
{
if (result.Status == TaskStatus.Faulted)
{
foreach (var ex in result.Exception.InnerExceptions)
{
Console.WriteLine(ex.Message);
}
}
});
</pre>
<br />
3. 使用 await
<br />
<pre class="prettyprint linenums:1">static void Main(string[] args)
{
FooAsync();
Console.ReadLine();
}
private static async Task FooAsync()
{
try
{
await Task.Run(() =>
{
throw new Exception("occurs in task");
});
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
</pre>
<br />Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-80396344245341739542018-08-19T17:51:00.003+08:002018-08-19T19:55:30.193+08:00【C#】Thread 101<br />
<a name='more'></a>外緒最主要的功能是<b>防止一個耗時過長的任務 block 主緒</b>導致 UI 不能操作且程式看起來像沒有回應。<br />
<br />
<b>多緒並不總是比較快</b>,比方多個執行緒存取相同的資源,進行短時間的簡單計算,資源的分配與執行緒的調動成本最終可能比計算更高。<br />
<br />
執行緒的使用時機應該是<br />
<ol>
<li>以外緒防止 UI hang 住</li>
<li>同時大量獨立的要求</li>
<li>需要知道進度</li>
<li>耗時長的運算</li>
<li>有優先度或順序性的運算</li>
</ol>
比方讀取成績、計算加權排名;<br />
在A緒每完成讀取成績時就可以吐給使用者先看、並同時以B緒運算加權分數並加入排名樹。<br />
<br />
<b>前/背景緒
</b><br />
由 new Thread() 建出的緒預設為前景緒,除非強制關閉,否則 Process 會等到所有前景緒結束才關閉。<br />
<pre class="prettyprint linenums:1">static void Main(string[] args)
{
Thread t = new Thread(() =>
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i + 1);
Thread.Sleep(1000);
}
});
// t.IsBackground = true;
t.Start();
Console.ReadLine();
}
</pre>
若按下 Enter 觸發 Console.ReadLine() cmd 也不會馬上關閉,而是等到 t 執行完,若 IsBackground = true 則即使 t 未執行完 cmd 也會馬上關閉。<br />
一般我們會用的是背景緒。<br />
<br />
<b>Thread Pool</b><br />
提供已預先建好並納管的背景緒,降低執行緒的建構/回收成本。<br />
一般會從這裡抽而不是自己建;從這抽出的緒完成任務後會回歸,降低反覆建置的成本。<br />
<br />
<br />Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-45383301268573209262018-07-03T17:54:00.004+08:002018-07-03T17:54:45.819+08:00【Dairy】Word multilevel list convex1.1 xxx<br />
1.2 xxx<br />
...<br />
1.10 xxx<br />
凸一大格的問題<br />
<br />
<a name='more'></a><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-4GreNo7XfRg/WztHsB0TvlI/AAAAAAAAFlw/mJe0sDkQhtY-jgFKYbtaBzUrGSyUgWoigCKgBGAs/s1600/Image1.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="505" data-original-width="579" height="347" src="https://3.bp.blogspot.com/-4GreNo7XfRg/WztHsB0TvlI/AAAAAAAAFlw/mJe0sDkQhtY-jgFKYbtaBzUrGSyUgWoigCKgBGAs/s400/Image1.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-9aSPYI3JyNo/WztHsP3IBjI/AAAAAAAAFlw/vnBfO85R7RMiIN_JRmsEMtA5Pjp06OCNACKgBGAs/s1600/Image2.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="493" data-original-width="633" height="311" src="https://2.bp.blogspot.com/-9aSPYI3JyNo/WztHsP3IBjI/AAAAAAAAFlw/vnBfO85R7RMiIN_JRmsEMtA5Pjp06OCNACKgBGAs/s400/Image2.jpg" width="400" /></a></div>
<br />Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-61958512441932177482018-06-28T17:34:00.000+08:002018-06-28T17:43:22.209+08:00【SQL】The transaction log for database is full due to 'LOG_BACKUP'交易紀錄滿了的處理<br />
<br />
<a name='more'></a>清紀錄
<br />
<pre class="prettyprint linenums:1"> -- Truncate the log by changing the database recovery model to SIMPLE.
ALTER DATABASE MyDB
SET RECOVERY SIMPLE;
GO
-- Shrink the truncated log file to 1 MB.
DBCC SHRINKFILE (MyDB_log, 1);
GO
-- Reset the database recovery model.
ALTER DATABASE MyDB
SET RECOVERY FULL;
GO
-- select name from sys.database_files; 查 log file name(沒改名的話一般都是 dbName_log)
</pre>
<br />
ref: <a href="https://stackoverflow.com/questions/21228688/the-transaction-log-for-database-is-full-due-to-log-backup-in-a-shared-host">SO</a><br />
擴充等其他應對:<a href="https://docs.microsoft.com/zh-tw/sql/relational-databases/logs/troubleshoot-a-full-transaction-log-sql-server-error-9002?view=sql-server-2017">MSDN</a>Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-81230884819529483672018-06-25T13:47:00.004+08:002018-08-19T19:28:04.818+08:00【C#】Lock讓多執行緒在同時無法存取同段程式<br />
<br />
<a name='more'></a>你的帳戶有100塊,你拿了金融卡去提100,但很巧的是,你媽也拿了你的本子去提100,如果兩人同時存取同帳戶,且都提款成功,那這個帳戶就變成-100了。<br />
<pre class="prettyprint linenums:1">static decimal _balance = 100;
private static readonly object _lockObj = new object();
public static void Withdraw(decimal amount)
{
//lock (_lockObj)
//{
if (amount > _balance)
{
throw new Exception("Insufficient funds");
}
_balance -= amount;
//}
}
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("========================================");
_balance = 100;
var ta = Task.Run(() =>
{
try
{
Withdraw(100);
Console.WriteLine("Task A withdraw");
}
catch (Exception ex)
{
Console.WriteLine($"Task A {ex.Message}");
}
});
var tb = Task.Run(() =>
{
try
{
Withdraw(100);
Console.WriteLine("Task B withdraw");
}
catch (Exception ex)
{
Console.WriteLine($"Task B {ex.Message}");
}
});
Task.WaitAll(new Task[] { ta, tb });
Console.WriteLine($"balance: {_balance}");
Console.WriteLine("========================================");
}
Console.ReadLine();
}</pre>
試5次左右應該就有機會試出來。<br />
<br />
為了防止多緒發生這種情況,我們會使用 Lock 進行保護,lock 的種類依應用細節不同有蠻多的,但最基本款就是<br />
<pre class="prettyprint linenums:1">lock(_lockObj)
{
// critical section
}</pre>
<br />
第一次用 lock 很容易發生的誤會是以為 lock 的保護對象是資源,但實際上 lock 保護的對象是<a href="https://zh.wikipedia.org/wiki/%E8%87%A8%E7%95%8C%E5%8D%80%E6%AE%B5">存取該資源的程式碼(critical section)</a>,如前 Demo 解註解,可以看到 lock {} 中的判斷領錢與實際扣錢的程式碼才是其保護對象。<br />
<br />
整體來說可以想成這樣<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-kanmKsfj_7Q/WzCBcUZnQqI/AAAAAAAAFkU/7aIsTMkCTeIxJfxjn1iJTnLLzMzt13bXwCKgBGAs/s1600/door.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="226" data-original-width="520" src="https://3.bp.blogspot.com/-kanmKsfj_7Q/WzCBcUZnQqI/AAAAAAAAFkU/7aIsTMkCTeIxJfxjn1iJTnLLzMzt13bXwCKgBGAs/s1600/door.jpg" /></a></div>
<div class="separator" style="clear: both;">
</div>
<br />
至於 _lockObj 就只是要有個變數可以讓 lock statement 標現在有沒有 thread 已經進來了,細節參考: <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement">lock</a>。<br />
<br />
<br />Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-52244811336158029382018-06-24T23:29:00.002+08:002018-08-19T19:28:14.452+08:00【C#】Synchronize thread多執行緒同步<br />
<br />
<a name='more'></a><br />
某玩具需要 零件A、B組裝,零件由個別的產線製作,假設製作速度 A>B;那 A完成後就要在組裝台等 B 送來才能拼組。 在這個情境中 產線 A、B 即是 thread,生產零件是 thread 進行的任務;A 完成後等待 B 的這個行為就是多緒同步。<br />
<br />
傳統的方法<br />
用 EventWaitHandle(也就是 <b>AutoResetEvent </b>或 <b>ManualResetEvent</b>) 控制子緒<br />
<pre class="prettyprint linenums:1">static AutoResetEvent handleA = new AutoResetEvent(false);
static AutoResetEvent handleB = new AutoResetEvent(false);
static void Main(string[] args)
{
for (int i = 0; i > 2; i++)
{
Task.Run(() =>
{
Console.WriteLine("Start to create component A");
Thread.Sleep(2500);
Console.WriteLine("Finished component A");
handleA.Set();
});
Task.Run(() =>
{
Console.WriteLine("Start to create component B");
Thread.Sleep(5000);
Console.WriteLine("Finished component B");
handleB.Set();
});
Console.WriteLine("Wait for components");
handleA.WaitOne();
handleB.WaitOne();
// 上面兩行可以取代成 WaitHandle.WaitAll(new WaitHandle[] { handleA, handleB });
Console.WriteLine("Assemble the toy");
Console.WriteLine("Toy created");
}
Console.ReadLine();
}
</pre>
每個需要停等的任務要有一個 handle,它的建構引數 initState = false 表示 unsignaled,在 unsignaled 的狀態下 handle.WaitOne() 會 block 當前的 thread,直到 handle.Set() 送出釋放訊號為止。<br />
在 Demo 中我們在兩個 thread 開始後就用 handleA, B 都 WaitOne()把主緒 block 住,等待個別任務的最後一行 Set() 對 handle 個別解鎖;兩個 handle 都解鎖之後主緒即恢復運行。<br />
<br />
<b>AutoResetEvent vs ManualResetEvent</b><br />
兩者的差異就就像字面上一樣,ManualResetEvent 在 Set() 之後需要手動 Reset() 調整回 unsignal 的狀態,否則 WaitOne() 將不會發生作用;把前面 Demo 的 AutoResetEvent 都改成 ManualResetEvent 即可觀察到第二 loop 時 WaitOne 未 block 主緒。<br />
ref: <a href="https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/concepts/threading/thread-synchronization">MSDN</a><br />
<br />
Quick sum up<br />
1. 一個任務,一個 handle<br />
2. EventWaitHandle 的 ctor 一般是給 false,因為我們希望它一開始就是可以 block 緒的狀態<br />
3. handle.WaitOne() 會 block 當前的 thread;handle.Set() 則會釋放<br />
4. AutoResetEvent 比較常用,因為不用特意去 Reset()<br />
<br />
傳統方法不管是寫還是閱讀都不甚直觀,之所以還是提一下是因為常 mantain 到,來看看新方法吧!<br />
<br />
<b>TPL Task.WaitAll()</b><br />
<pre class="prettyprint linenums:1">for (int i = 0; i < 2; i++)
{
Task taskA = Task.Run(() =>
{
Console.WriteLine("Start to create component A");
Thread.Sleep(2500);
Console.WriteLine("Finished component A");
});
Task taskB = Task.Run(() =>
{
Console.WriteLine("Start to create component B");
Thread.Sleep(5000);
Console.WriteLine("Finished component B");
});
Console.WriteLine("Wait for components");
Task.WaitAll(new Task[] { taskA, taskB });
Console.WriteLine("Assemble the toy");
Console.WriteLine("Toy created");
}
</pre>
是不是好懂一百倍? 語意簡單到不用解釋。<br />
<br />Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-68465842304442299252018-06-24T21:04:00.003+08:002018-06-24T21:04:56.812+08:00【C#】Generics從之前寫的文章拆出來<br />
<br />
<a name='more'></a>
<b>Generics#2 (再談泛型)</b><br />
泛型的功能是傳入 Class T 為類別或方法的參數;這提供我們一個彈性,就是在執行時期才決定某些東西的型別,就以前面的 List 為例,我們來看微軟的 src code<br />
<pre class="prettyprint linenums:1">namespace System.Collections.Generic {
using System;
...
public class List<T> : IList<T>, ...
{
...
private T[] _items;
...
</pre>
不重要的地方我截掉了,可以看到它是用普通陣列為底去實作的,對於 List 的操作(比方 Sort();)來說陣列元素是什麼型別完全沒有影響,但如果我們沒有 T,要定義 List 中的普通陣列要嘛就是 object[] _items 操作完出去在轉型,不然就是建構子就要傳具型別的陣列進來,像 List(SomeType[] array)。<br />
<br />
但對前者,問題是效能差(因為要轉型),而且多了不必要的轉型錯誤可能性,後者則是泛用性低落,每多一個型別就被迫要寫一個多載,造成大量的程式碼重覆。所以在需要<span style="background-color: #fff2cc;">把型別當參數</span>的這個背景需求下發展了泛型這個功能。Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0tag:blogger.com,1999:blog-7578039559471749169.post-54394079943553058492018-06-21T11:34:00.001+08:002018-06-21T11:37:15.062+08:00【SQL】Close single user mode在 master 強制設 DB 回多使用者<br />
<br />
<a name='more'></a>
<pre class="prettyprint linenums:1">-- Find spid
SELECT sd.[name], sp.spid, sp.login_time, sp.loginame
FROM sysprocesses sp
INNER JOIN sysdatabases sd on sp.dbid = sd.dbid
WHERE sd.[name] = <DB_NAME>
KILL <spid>
GO
SET DEADLOCK_PRIORITY HIGH
GO
ALTER DATABASE <DB_NAME> SET MULTI_USER WITH ROLLBACK IMMEDIATE
GO
</pre>
Circle Hsiaohttp://www.blogger.com/profile/05258767397298463170noreply@blogger.com0