æªç¥ã®ãã©ãã¯ãèžã¿ã€ããããšã¯ç°¡åã§ã¯ãããŸããã誰ããããªãã®åã§ãã®ãã©ãã¯ãã©ã®ããã«èžãã§ããããåŠã¶ã®ã¯ãã£ãšç°¡åã§ãã ç§ã¯ããã¥ã¡ã³ããŒã·ã§ã³ãå匷ããããã®éãæã£ãŠããŸãããåèæžãšããŠäœ¿çšããŸãããŸãããŒãããäœããå匷ããã«ã¯ãå€ãã®æéãšåŽåãããããŸãã ãŸãããµã€ã¯ãªã³ã°ã®ãããã¯ã§ã¯ãåŠç¿ããã»ã¹ãçæãªã©ããã¹ãŠç¶²çŸ ããŠããŸãã æ®å¿µãªããšã«ãèå³ã®ãããããã¯ã«é¢ããååãªè©³çŽ°ãªèšäºãèŠã€ããããªãã£ãã®ã§ãæåããæåŸãŸã§å匷ããŠãèªåã§èšäºãæžãããšã«ããŸããã
å¿ èŠã«å¿ããŠãããã»ã¹ãã¢ãããŒãããŸãã¯ã€ããªãã®ãŒããã¹ã¿ãŒãããã£ãã®ã§ãããããã¯TDDïŒå¥åãã¹ãé§åéçºïŒãšåŒã°ããŸãã ãŸããè£å©æè¡ãšããŠããã¹ãã®äžéšã§ãMoqãã¹ããã¬ãŒã ã¯ãŒã¯ã䜿çšãããŸããã ä»åŸã¯ããã¢ãŒããã¯ãããšããŠã®çµéšãå¿ èŠãªã®ã§ãå®å šã«æ£ããéçºããããšã¯ã§ããªãã£ããšèšããŸãã ããã€ãã®ãããã¯ãããçŽããªããã°ãªãããç§ãæžãããã¹ãã±ãŒã¹èªäœã¯ãã¯ã©ã¹ãäœãã©ã®ããã«è¡ãã¹ããããŸã å®å šã«èªèããŠããŸããã§ããã ããããç©äºã¯åé²ããçµéšãç©ãŸãã次åã¯ãã£ãšç°¡åã«ãªãã¯ãã§ãã é·ãéæäœæ¥ã§ãã¹ã¿ãŒããŠãã2çªç®ã®ãã¯ãããžãŒã¯ãäŸåé¢ä¿ãšIoCã³ã³ãããŒã®å®è£ ã§ãã éçºã§ã¯ãæãå°è±¡çãªAutofacã䜿çšããŸããã
ãµã€ã¯ãªã³ã°ã®ããŒã
é·ãééžæããå¿ èŠã¯ãããŸããã§ãããã解決çã¯æåéãèªåã§ãã£ãŠæ¥ãŸãã-ãã£ã«ã¿ãªã³ã°ãšèšå®å¯èœãªåºå圢åŒã§èªåã®ãã¬ãŒãæžãããšã§ãã ASP.NetãšMVC3ãã¬ãŒã ã¯ãŒã¯ã«é¢ããæåã®èšäºãæžãããã£ãã®ã§ãã ãã ããMVC4ã«ç§»è¡ããããšã¯ãã§ã«çã«ããªã£ãŠããŸãã ã¡ãªã¿ã«ããã¯ãããžãŒã®äžã§ã¯ãEntity Frameworkã䜿çšããããšã«ãªã£ãŠããŸãã äž»é¡ã«é¢ããäž»é¡ã«é¢ããèšäºã¯æ¢ã«ãããŸãããèè ã¯çŽæãå®äºããã«å§¿ãæ¶ããŸããã
ããã§ã¯ããªããã¬ãŒã«ãã£ãŠäžæãããã®ã§ããïŒ ãã¡ããããã®ã¢ããªã±ãŒã·ã§ã³ãäœæããéçšã§ããã°ã®å¿ èŠæ§ãçããŸããã NuGetã§NLogãå ¥æããããšããå§ãããŸãããããããç 究ããçµæããã¬ãŒãæžãããšã¯é¢çœãã ãã§ãªãæ£åœã§ãããšããçµè«ã«éããŸããã ç§ã¯èªåã§ãã§ãã¯ããŸããã§ããããã€ã³ã¿ãŒãããã®ã¬ãã¥ãŒããå€æãããšãlog4netã¯ãããããé ããããèæ ®ããŸããã§ããã
ç§èªèº«ã¯ãã¬ã³ã ã§åããŠãããæšæºã®syslogã«ã¯ãªãæ©èœãå¿ èŠã«ãªã£ããšãã¯ããã§ã«ãã¬ãŒãšé£æºããå¿ èŠããããŸããã ããã¯IDã«ãããã£ã«ã¿ãªã³ã°ã§ãã ãµã€ãã1æéã«3äžä»¶ã®åŒã³åºããåŠçããå Žåããã°ã100ïŒ åçŸããããšããŠããã¡ã¬ãã€ãåäœãã®ã¬ãã€ãåäœã®ãã°ã§èŠã€ããããšã¯ããã»ã©ç°¡åã§ã¯ãããŸããã ã¯ãããã¹ãŠã®ã·ã¹ãã ã§ã®ã¬ãã€ãã®ãã°ãä¿åã§ããããã§ã¯ãããŸãããäžéšã®å Žæã§ã¯ãã©ãã·ã¥ã¢ã¯ãŒã§æ°åã®ãã©ãã£ãã¯ããååŸã§ããªãã·ã¹ãã ããããé話èªäœã®é·ããé·ããªãå ŽåããããŸããã€ãŸããé話ã®éå§ãŸãã¯çµäºããã°ã«èšé²ãããªãå ŽåããããŸãã ãã®ããããäžããããšããã¢ã€ãã¢ãçãŸããŸãããã³ãŒã«ã«ããŒã¯ãä»ããŠã圌ã ãããã°ã«èšé²ãããããã«ããŠæ£ããããšã匷調ãããšããããšã§ãã ããŠããŸãã¯ããã€ãã®åŒã³åºããããã®ãã°ãå®æçã«çºçããçªå·ã«ã®ã¿ã syslogã¯ãã»ãã·ã§ã³å ã®èå¥åããªãã¬ãŒã¿ãŒãæå®ããèå¥åã®ãªã¹ããšæ¯èŒãããã¯ãã«æ£åžžã«çœ®ãæããããŸããã èå¥åã¯ã端æ«ã®äžæã®ã¢ãã¬ã¹ãšãã€ã€ã«çªå·ã®äž¡æ¹ã«é¢é£ä»ããããŠããŸããã ç§ã®ASP.Netã¢ããªã±ãŒã·ã§ã³ã§ã¯ããã£ã«ã¿ãªã³ã°ã¯ãŠãŒã¶ãŒIDã«ãã£ãŠæ³å®ãããŠããŸããã ãã¡ãããããã¯ããã§ã¯ããŸãæ£åœåãããªããããããŸãããããã¬ãŒããã®æ©èœãå¿ èŠãšãããšæ±ºããã®ã§ãããããå¿ èŠããããŸãã
NLogã®ãœãŒã¹ã³ãŒãã調ã¹ãŠèŠã€ãã2çªç®ã®èªè»¢è»ã®æ©äŒã ãã®äžã§ãã»ãšãã©ãã¹ãŠã®ã¢ã¯ã·ã§ã³ã¯åŒã³åºãã¹ã¬ããã®ã³ã³ããã¹ãã§å®è¡ãããéåæçã«ã¿ãŒã²ãããžã®çŽæ¥æžã蟌ã¿ã®ã¿ãå®è¡ãããŸãã åŸã§ç¢ºä¿¡ããããã«ãããã¯ããã©ãŒãã³ã¹ã«ããªãã®ãã¡ãŒãžãäžããŸãã
å¥ã®ã¹ã¬ããã«æäœãé 眮ãã
ãã®æäœã¯ããã«å¥ã®ã¯ã©ã¹ã«ã«ãã»ã«åããŸããã ã¯ã©ã¹ã¯ããã¹ãŠã®ã¡ãã»ãŒãžãåŠçãããã¹ããªãŒã ãéå§ãããããã®ã¡ãã»ãŒãžããã®ã¹ããªãŒã ã«éä¿¡ã§ããããã«ããŸãã ã¡ãã»ãŒãžã«ã¯ããã°ã®ããã¹ããã¬ãã«ãããã³ãã®ä»ã®æ å ±ãå«ãŸããŸãã ããã¯ã¿ã¹ã¯ã解決ããããã«å¿ èŠã§ã-ãã°ãéä¿¡ããã¹ã¬ããã®ã³ã³ããã¹ãã§ã¢ã¯ã·ã§ã³ã®æ°ãæå°éã«æããããã
åºç€ãšããŠãVisual Studioã«å«ãŸããŠããèšèªãµã³ãã«ããThreadSyncã®äŸãåãäžããŸããã ãã¡ãŒã¹ãã¯ã©ã¹ã®ã€ã³ã¿ãŒãã§ãŒã¹ïŒ
public delegate void ReceiveHandler<T>(T item); public interface IQueued<T> { event ReceiveHandler<T> OnReceive; event Action OnTimeout; bool Active { get; } void setTimeout(int timeout); void Send(T msg); void Terminate(); }
ãã©ã°ã¯ãThreadRunå éšã¡ãœããã®éå§æã«èšå®ãããçµäºæã«ãªã»ãããããŸãã OnReceiveã€ãã³ãã¯ãã¹ããªãŒã ãæ°ããã¡ãã»ãŒãžãåä¿¡ãããšãã«çºçããŸãã åŒæ°ããªã²ãŒãåã®ãã£ã¹ããåé¿ããããã«ãã€ãã³ãããªã²ãŒãåãäœæãããŸããã ã¿ã€ã ã¢ãŠãã¯ããã£ã¹ã¯ãžã®çŽæ¥æžã蟌ã¿ã§ã¯ãªããããšãã°StringBuilderãªã©ã®æåã®ãããã¡ãžã®æžã蟌ã¿ãèš±å¯ããããã«äœæãããŸããã æåŸã®ã¡ãã»ãŒãžãåä¿¡ããŠââããæå®ããæéãçµéãããšãOnTimeoutã€ãã³ãã1åããªã¬ãŒãããæåŸã«åä¿¡ãããã°ããã£ã¹ã¯ã«éä¿¡ãããããšãä¿èšŒãããŸãã
ã¯ã©ã¹ã«ã¯2ã€ã®ãªãã·ã§ã³ããããçç±ã«å¿ããŠéžæã§ããŸãã 1ã€ã®ãªãã·ã§ã³ã¯ã¹ã¬ãããéå§ããŸãããTerminateãåŒã³åºãå¿ èŠããããŸãã
thread = new Thread(ThreadRun); thread.Start();
åãã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ãã2çªç®ã®ã¯ã©ã¹ã¯ãç¬èªã®ã¡ãœãããæšæºã®ThreadPoolã«è¿œå ããŸãã ç¹ã«ãã¡ã€ã³ã¢ããªã±ãŒã·ã§ã³ãæ¢ã«ããŒã«ã®è€æ°ã®ã¹ã¬ããã䜿çšããŠããå Žåããã®ã¹ã¬ããã¯éå§æã«éåžžã«é ããããšããããŸãã 1ã€ã®åã³-TerminateïŒïŒãåŒã³åºããŠå®äºããå¿ èŠã¯ãªããã¢ããªã±ãŒã·ã§ã³ãéãããšèªåçã«éããŸãã
ThreadPool.QueueUserWorkItem(ThreadRun);
ã³ã³ã¹ãã©ã¯ã¿ãŒã¯ãå ¥åãšããŠManualResetEventãåãå ¥ããŸãããã®å ¥åã¯ãã¹ã¬ããã§åäœããè€æ°ã®ã¯ã©ã¹ã«äŸçµŠãããéäžåãããã¢ããªã±ãŒã·ã§ã³çµäºã€ãã³ããšããŠäœ¿çšãããŸãã ãã¬ãŒã§ã¯ããã䜿çšããŸããã§ãããã念ã®ãããã®æ©äŒãè¿œå ããŸããã å®äºã€ãã³ãã«å ããŠãã€ãã³ããæ©èœããããã«äœ¿çšãããŸããããã¯ãæ°ããã¡ãã»ãŒãžããã¥ãŒã«å°çããããšãæå³ããŸãã ãããªæã
EventWaitHandle[] events = new EventWaitHandle[2]; ... events[0] = new AutoResetEvent(false); events[1] = terminateEvent ?? new ManualResetEvent(false);
ããã§ãTerminateã¡ãœããã®ã¿ã¹ã¯ãã€ãã³ã[1]ã1ã«èšå®ããããšã§ããããšã¯éåžžã«æçœã§ãã
éä¿¡ããã¡ãã»ãŒãžãä¿åããããã«ããã¥ãŒãã¥ãŒã䜿çšããŸããã SendïŒïŒã¡ãœããã¯ãäŸããåçŽã«ã³ããŒãããŸãïŒ
lock (queSync) { queue.Enqueue(msg); } events[0].Set();
å察åŽã§ã¡ãã»ãŒãžãåä¿¡ããããã«ããåéãã¹ããªãŒã ã«ãããã¥ãŒãããã¯ã®æéãæå°éã«æããããã«ãã¡ãã£ãšããããªãã¯ã«é Œãããšã«ããŸããã ãã®ããããã¥ãŒèªäœã§ã¯ãªããåå¥ã«äœæããããªããžã§ã¯ãã«å¯ŸããŠããã¯ãè¡ãããŸãã åä¿¡ã¹ã¬ããã¯ç¡éã«ãŒãå ã§ã¹ãã³ããã€ã³ããã¯ã¹ã1ã«çããå Žåã«åºåãçæãããŸããã€ãŸããåè¿°ã®ããã«ãTerminateã¡ãœãããŸãã¯å€éšããåŒã³åºãããã€ãã³ã[1]ãæ©èœããããšãæå³ããŸãã
while ((index = WaitHandle.WaitAny(events, currentTimeout)) != 1)
WaitAnyã¡ãœããã¯ãã€ãã³ãã®1ã€ãããªã¬ãŒãããããããã©ã«ãã§ã¿ã€ã ã¢ãŠããç¡éã«èšå®ããããŸã§ã¹ã¬ããããããã¯ããŸãã ã€ãŸãããã¬ãŒã®ãããŒã¯ã¹ãªãŒããããã°ã®éä¿¡ãéå§ãããŸã§ã¢ããªã±ãŒã·ã§ã³ã®ããã©ãŒãã³ã¹ã«åœ±é¿ãäžããŸããã ããªã¬ãŒããããšããŸããã¿ã€ã ã¢ãŠããçºçãããã©ããã確èªãã察å¿ããã€ãã³ããã¢ã¯ãã£ãã«ããŸãã
if (index == WaitHandle.WaitTimeout) { OnTimeout(); currentTimeout= Timeout.Infinite; }
ããã®2è¡ç®ã¯ããŠããããã¹ãã®ããã«æ£ç¢ºã«è¡šç€ºãããŸããããã³ãŒãã£ã³ã°äžã«èŠéããŸããã ãã以å€ã®å Žåã¯ããã¥ãŒããã¡ãã»ãŒãžãååŸããå¿ èŠããããåã¡ãã»ãŒãžã§OnReceiveã€ãã³ããçºçããŸãã å ã»ã©èšåãããããªãã¯ãã¯ãã³ãŒãã«è¡šç€ºãããŠããŸãã
Queue<T> replacement = new Queue<T>(); Queue<T> items; lock (queSync) { items = queue; queue = replacement; } foreach (T t in items) { OnReceive(t); } currentTimeout = timeout;
ãã®ã¯ã©ã¹ã®ãã¹ãŠã®éèŠãªãã€ã³ãããŸãããŸãã¯ã¢ãžã¥ãŒã«ã«ã€ããŠã¯ãä»ã®ãã¹ãŠã®ã¯ã©ã¹ãšåæ§ã«ããã®å®å šãªã³ãŒãããªããžããªã«ãããŸããèšäºã®æåŸã«ãªã³ã¯ãæ²èŒãããã®å 責äºé ãç¹°ãè¿ããŸããã
ãã§ã«èšäºãæžããŠããæç¹ã§ãConcurrentQueueã䜿çšããŠåãããšãè¡ããšããã¯ã¬ã€ãžãŒãªã¢ã€ãã¢ãæãæµ®ãã³ãŸãããåœç¶ãäžèšã®ããªãã¯ã¯ãªããå®å šã«ããããã³ã°ã¯ãããŸããã åæã«ãäž¡æ¹ã®ã¿ã€ãã®ã¹ããªãŒã ãäœæããå¯èœæ§ãäœããã®åœ¢ã§æ®ãå¿ èŠããããŸãã ãããã£ãŠãã€ã³ã¿ãŒãã§ã€ã¹ã®èåŸã«ã¹ããªãŒã ã®äœæãã«ãã»ã«åããããšã«ããŸããããããIStarterãšåŒã³ãŸããã¯ã©ã¹ã¯ããããåäžã®ã¡ãœããã§æ§æãããŸãã ã¡ãªã¿ã«ãããã§ã¯ã©ã ãåŒã䜿çšããããšã¯éåžžã«å¯èœã§ãããç§ã®ãšã¹ããã£ã¹ãã¯ããã«å察ããŸããã ãã®çµæããããªããžã®ãã¡ãåŽãã«ã¯ããã¯ãšã€ã³ã¿ãŒããã¯ã®2ã€ã®ã¯ã©ã¹ãããããããªããžã®å察åŽãã«ã¯2ã€ã®ã¯ã©ã¹ãããããããã®ãããŒãéå§ãã2ã€ã®ãªãã·ã§ã³ããããŸããä»»æã®çµã¿åããã§äœ¿çšã§ããŸãã GoFã®ãå®è£ ã§ã¯ãªããã€ã³ã¿ãŒãã§ã€ã¹ãšå¯Ÿè©±ããããšããã€ããªãã®ãŒã®é åïŒcïŒã¯ãããŒã¿ãšå¯Ÿè©±ããä»ã®ã¯ã©ã¹ã«è§Šããå¿ èŠããªããšããäºå®ã ãã§ãªããåäœãã¹ããå€æŽããå¿ èŠããªããšããäºå®ã§è¡šãããŸãã ã 絶察ã«ã ç¹å®ã®ãªããžã§ã¯ããäœæããããªã¢ãŒãã£ãã¯ãªæ¹æ³ãå€æŽããã ãã§ããã¹ãŠã®ãªãã·ã§ã³ã«ãããã®ãã¹ããæäŸãããŸãã
TDDã®å§ãŸã
ç§ã¯ãã®ãããã¯ã«ã€ããŠå°ãçè«çã§ãã æåã«ãæåã®ã¯ã©ã¹ãš2çªç®ã®ã¯ã©ã¹ãåãã¯ã©ã¹ã®äŸã§ã¯ãTDDã§ã¯éçºåäœãèŠçŽã§ããŸããã§ãããæåã«ãã¹ããè¡ãã次ã«ã³ãŒãèªäœãäœæããŸããã ç§ã®éçºã®éçã¯ã次ã®æ®µéãçµãŸãããåäœããã³ãŒããäœæãããã¹ãã±ãŒã¹ãäœæããæåãš2çªç®ã®äž¡æ¹ã調æŽããŠãæšæºã«ããŸããã ãã®åŸããã¹ãã¯ãçã§ãããšèªèããããåŸã«ç¶ããªãã¡ã¯ã¿ãªã³ã°ã¯ãããããããã«åºã¥ããŠããå¯èœæ§ããããŸãã å°ãªããšãåå¿è ã«ãšã£ãŠããã®ã¢ãããŒãã«ã¯çåœã®æš©å©ããããšèããçç±ïŒæãåçŽãªé¢æ°A = B + Cãèæ ®ããå Žåããã®é¢æ°ã®ãã¹ãã¯åŒC1 = A-Bã§ææ¡ãããæ¯èŒCã«åºã¥ããã¹ãã®æåã®çµè«== C1ã ããã§ã®ãšã©ãŒã¯ããã¹ããããæ©èœãšãã¹ããããæ©èœã®äž¡æ¹ã«å«ãŸããŠããå¯èœæ§ããããŸãã ããã«ãã¢ã¯ã·ã§ã³ãå€ãããããã¹ãçºçãããããªããŸãã ãã®æç¹ã§ããªããã¹ããå¿ èŠãªã®ãçåã«æããããããŸããããçãã¯èªç¶ã«ãã§ã«ååšãããã¹ãŠãç§ãã¡ã®åã«å®åŒåãããŠããŸãã ãã¹ãã§ãåæ Œãã瀺ãã«ã¯ãæ¡ä»¶ã®1ã€ãæºããããŠããå¿ èŠããããŸãã äž¡æ¹ã®æ©èœã«ãšã©ãŒããªããããã¡ãã¡ã«ãšã©ãŒãåæã«ååšããŠããŸãã äž¡æ¹ã®ãšã©ãŒãçºçãã確çã¯ãããããã®ãšã©ãŒã®ç¢ºçãããåå¥ã«å°ãããªããŸããç¹ã«ãããã«ååšããã ãã§ã¯ååã§ã¯ãªãããããšã©ãŒãçžä¹çã§ãããã€ãŸãçžäºã®åœ±é¿ãè£åããå¿ èŠããããŸããããã®ç¢ºçã¯ããã«äœããªããŸãã ã€ãŸãããã¹ããèšè¿°ãããã¹ãŠã®åªåã¯ããšã©ãŒã®å¯èœæ§ãæžããããšãçŽæ¥ç®çãšããŠããŸãã ãã ããåã人ããã¹ããšã³ãŒãã®äž¡æ¹ãæžãå Žåãåãééãããã確çã¯ãããã«é«ããªããŸãã ããŠã倧äžå€«ãç§ã«ãšã£ãŠã¯èªè»¢è»ã®ããã§ãããããŠäœããã§ã«è¯ãã§ããã
æåã®ãã¹ãã®äœæã«ç§»ããŸãããã ãããè¡ãã«ã¯ããŸãIQueuedã€ã³ã¿ãŒãã§ã€ã¹åãå³ã¯ãªãã¯ãã察å¿ããã¡ãã¥ãŒé ç®ãéžæããŠããã¹ããã³ãã¬ãŒããäœæããŸãã ãããã£ãŠããã®ã¯ã©ã¹ããã¹ãããã«ã¯äœãå¿ èŠã§ãã åç¬ã§ãã¹ãããããšã«ãªã£ãŠããã®ã§ããµããžã§ã¯ãã¯ã©ã¹ãšå¯Ÿè©±ããã¯ã©ã¹ã®mokiïŒæš¡å£è ïŒãäœæããå¿ èŠããããŸãã å¥ã®ãã€ã³ã-ãã¹ãã®ç®çã¯ã€ã³ã¿ãŒãã§ã€ã¹ãéžæããããšã§ãããæåã«ãã¹ãããç¹å®ã®ã¯ã©ã¹ã2ã€ãããåŸã§2察2ã®4ã€ã®çµã¿åããããã£ããããæ°ããäœæãããã¹ãã¯ã©ã¹ã«æœè±¡ä¿®é£Ÿåãä»ããŠæ±çšãã©ã¡ãŒã¿ãŒãè¿œå ããã®ãçã«ããªã£ãŠããŸãã
[TestClass()] public abstract class IQueuedTest<T>
ã¯ã©ã¹ã¯æœè±¡ã¯ã©ã¹ãªã®ã§ããã¹ãã¯ã¯ã©ã¹ã«å¯ŸããŠçŽæ¥å®è¡ãããŸããããã¡ãããã¯ã©ã¹ããç¶æ¿ããããã¹ãŠã®ãã¹ãã¯ã©ã¹ãå®è¡ãããŸãã
ãŸãããµãŒãã¹ã¯ã©ã¹ã®ã³ã³ã·ã¥ãŒãã·ãã¥ã¬ãŒã¿ãå¿ èŠã§ãã
class Tester<T1>
ãã®ã¯ã©ã¹ã¯ããã¹ããããã¯ã©ã¹ã®ã€ãã³ãããµãã¹ã¯ã©ã€ãããã€ãã³ãã®ããªã¬ãŒãæ€èšãããã®ã€ãã³ãã§äœãèµ·ãã£ãããèšæ¶ããŸãã
public Tester(IQueued<T1> tested) { tested.OnReceive += Received; tested.OnTimeout += TimeOut; } void TimeOut() { timedCount++; } void Received(T1 item) { Thread.Sleep(delay); receivedCount++; lastItem = item; }
ãã®å éšã¯ã©ã¹ã«å ããŠãç¹å®ã®ãªããžã§ã¯ããäœæããã¡ãœãããå¿ èŠã«ãªããŸããããã«ããããã¹ãŠã®çžç¶äººããªãŒããŒã©ã€ãããå¿ èŠããããŸãã
protected abstract IQueued<T> createSubject(); protected abstract T CreateItem();
ã ãããå®éã«ãã¹ããæžãããšã«ã ã¡ãªã¿ã«ããã®ãããªèšäºãèªãã§ãããšãèè ã¯ã¬ãŒããçç¥ããæ¢æã®ãœãªã¥ãŒã·ã§ã³ãæäŸããŠããããšã«æ°ä»ããŸããã ããã€ãã®ã¬ãŒãã«ã€ããŠè©³ãã説æããŸãã ç§ãæåã«ééããåé¡ã¯ãã¹ã¬ããããŒã«ã§ã®éå§ã®åãé 延ã§ããã ã¢ããªã±ãŒã·ã§ã³ãèµ·åãããšãããŒã«ã¯å°æ°ã®ã¹ã¬ããã®ã¿ãä¿æããæ°ããã¹ã¬ããã10åã®1ç§ã§æž¬å®ãããé 延ã§ã®ã¿èµ·åããŸãã ãããŠããã¹ããã¬ãŒã ã¯ãŒã¯ã¯ãã¹ãã䞊è¡ããŠå®è¡ããŠããããã§ãã ãã®ããããæåããããŒã䜿çšãããã¹ãã¯æåããŸããããããŒã«ããã®ãããŒã§ã¯äžéšãåæ Œããäžéšã¯èœã¡ãŸããã ãããã£ãŠã2ã€ã®ãªãã·ã§ã³ããããŸããåããé·ããã¡ãœããã§ãã¹ãŠã®ãã¹ããéžæããŸããããã¯ããé«éã«å®è¡ãããŸãããäžè¬çãªå€å®ã1ã€ã ãçºè¡ããããåé¿çãèãåºããŸãã ç§ã¯æ¬¡ã®ããšãæãã€ããŸããïŒ
void ActivationTestHelper(Tester<T> tester, IQueued<T> subject) { int retry = 30; while (!subject.Active && retry > 0) { retry--; Thread.Sleep(SleepDelay); } Assert.AreEqual(true, subject.Active); }
30ã¯ãã¹ããªãŒã ãã¢ã¯ãã£ãã«ãªããŸã§ãåŸ æ©ããè©Šã¿ããã®åŸã¯ãã¹ãã®ã¿ã«é²ã¿ãŸãã ãã«ããŒã¯äœæåŸããã«åŒã³åºãããŸãã
ãããŠãåã³-ããããã¹ããæžãããšã«ã æåã®ãã¹ãã¯ãã¡ãã»ãŒãžãéåä¿¡ããããšã§ãã ã¯ã©ã¹ã®ã¿ã¹ã¯ã¯å¥ã®ã¹ã¬ããã«è»¢éããããšã§ããããšãããã£ãŠããããããã¹ã¿ãŒã¯ã©ã¹ãéä¿¡ã¹ããªãŒã ã®ã³ã³ããã¹ãã§ã¡ãã»ãŒãžãåä¿¡ããªãããšã確èªãããã®åŸæ£åžžã«åä¿¡ããããšã確èªããå¿ èŠããããŸãã ã¡ãªã¿ã«ããã¹ã¿ãŒãReceivedã¡ãœããã®ã³ãŒãã§50ããªç§ã®é 延ãæã£ãŠããã®ã¯ããã®ããïŒæåã®å ŽåïŒã§ãã ãã®é 延ãåŒã³åºãã¹ã¬ããã§çºçããå Žåãæåã®ã¢ãµãŒãã¯ãã¹ãã«å€±æããŸãã
[TestMethod()] public void SendTest() { var subject = createSubject(); var tester = new Tester<T>(subject); ActivationTestHelper(tester, subject); T item = CreateItem(); tester.delay = SleepDelay; subject.Send(item); Assert.AreEqual(0, tester.receivedCount);
次ã«ãã¡ãã»ãŒãžãéä¿¡ãããããšã確èªããããã«ã100ããªç§åŸ ã£ãŠããåä¿¡ããã¡ãã»ãŒãžã確èªããŸãã ååãšããŠããããã®å€ã¯æžããããšãã§ããŸããäž»ãªããšã¯ã2çªç®ã®é 延ãæåã®é 延ããã倧ããããšã§ãããããã§ã¯ãããã¯åççã§ã¯ãªããšæããŸãã 以äžã®ãã¹ãã«ãéãè²ããããã«ããããŒãå®äºããããšãå¿ããªãã§ãã ããã
Thread.Sleep(SleepDelay2); Assert.AreEqual(1, tester.receivedCount); Assert.IsTrue(tester.lastItem.Equals(item)); subject.Terminate(); }
次ã«ãã¿ã€ã ã¢ãŠããã¹ãã ãŸãããªããžã§ã¯ããäœæããã¢ã¯ãã£ããŒã·ã§ã³ãã«ããŒãå®è¡ããŸãã ã¿ã€ã ã¢ãŠããèšå®ããåŒã³åºãå ã¹ã¬ããã®ã³ã³ããã¹ãã§ã¯åŒã³åºããããåŸã§åŒã³åºãããããšã確èªããŸãã ãããŠäžåºŠã ãã
[TestMethod()] public void TimeoutTest() { var subject = createSubject(); var tester = new Tester<T>(subject); subject.setTimeout(SleepDelay); ActivationTestHelper(tester, subject); T item = CreateItem(); subject.Send(item); Assert.AreEqual(0, tester.timedCount); Thread.Sleep(SleepDelay3); Assert.AreEqual(1, tester.timedCount); }
ãã®ãã¹ãã§ã¯ãã¿ã€ã ã¢ãŠãå€ã®4åã§ãã200ããªç§ã®é 延ãèšå®ãããŸãããæåã®ãšã©ãŒã§ããèŠèœãšãããã£ããããã®ã¯ãã®ãã¹ãã§ããã åäœãã¹ãã¯å¿«é©ã§ããããšãå€æããŸãããããã¯ããšã©ãŒã®çµ¶å¯Ÿçãªå€§éšåãããããã¯ã·ã§ã³ãã ãã§ãªããã¢ã«ãã¡ãã©ã€ã¢ã«ã«ãåã°ãªãããšãæå³ããŸãã ãã¡ããããããã®ãšã©ãŒã¯ããã§æ€åºãããŸããããã¹ãã®èšè¿°ã«è²»ããããäœæ¥ã¯ããããã°ã®ããã«è¡ãããªããã°ãªããŸããã ãã®çµæãç·æ¥äºæ ããæ techniqueãªãéçºæéã«ãã£ãæéããäžå®éã®äœæ¥ãã·ããããäžçš®ã®æé管çæè¡ãã§ããŸããã ãããŠãããããã¹ãŠã¯ããªãã¡ã¯ã¿ãªã³ã°ã«ããã貎éãªå©ãã«èšåããªããŠããç§ãéäžã§çºæãããã®ã§ãã
æ®ãã®ãã¹ãã¯ãã¹ããªãŒã ã®å®äºã§ãã ã¹ããªãŒã ãåæ¢ãããã©ãã«ãäœãéä¿¡ãããªãããšã確èªããå¿ èŠããããŸãã ãã¹ãŠã®ãã¹ãã«å ±éã®æé ãçç¥ãããšã次ã®çµæãåŸãããŸãã
public void TerminateTest() { ... subject.Terminate(); subject.Send(item); Thread.Sleep(SleepDelay3); Assert.AreEqual(0, tester.receivedCount); Assert.AreEqual(0, tester.timedCount); }
ã€ã³ã¿ãŒãã§ã€ã¹ã«ã¯3ã€ã®ãã¹ããããããŸãããã2ã€ã®ç¹å®ã®ã¯ã©ã¹ãã¹ããªãŒã ãéå§ããããã®2ã€ã®ãªãã·ã§ã³ãããããã®äžã§ãéä¿¡ã¡ãã»ãŒãžãšããŠã®ã¯ã©ã¹ãšæ§é ã®åäœãåå¥ã«ç¢ºèªããããšã«ããŸããã ãªã8ã€ã®ç¹å®ã®ãã¹ãã¯ã©ã¹ãäœæããããã®ãã¡ã®1ã€ãæå®ããŸããç¹å®ã®ãã¹ãã±ãŒã¹ã®æ°ã¯24ã§ãããã¹ãæ§é ïŒ
public struct TestMessageStruct { public string message; //object reference field public int id; //value field }
ãããŠå®éã«ã¯ããªãã·ã§ã³ããã¹ãããç¹å®ã®ãã¹ãã¯ã©ã¹ïŒãããã¯ããããã¥ãŒãéåžžã®ã¹ã¬ãããæ§é ã
[TestClass()] public class IQueuedLockRegTest : IQueuedTest<TestMessageStruct> { protected override IQueued<TestMessageStruct> createSubject() { return new LockQueued<TestMessageStruct>(new RegularThreadStarter()); } protected override TestMessageStruct CreateItem() { var item = new TestMessageStruct(); var rnd = new Random(); item.id = rnd.Next(); item.message = string.Format("message {0}", item.id); return item; } }
ããã«é¢é£ããŠããçŽããªããã°ãªããªãç¹å®ã®å®éšãªããžã§ã¯ããäœæããã®ã¯ãç¹å®ã®ãã¹ãã¯ã©ã¹ã§ããã ãŸãããã®æ°ã2åã«ããªããã°ãªããŸããã§ããããã芧ã®ãšããããã¹ãèªäœãèšè¿°ããçèãããšããããå€§å¹ ã«å°ãªãæéãšåŽåããããããŸããã
ãã¬ãŒã€ã³ã¿ãŒãã§ã€ã¹ãšæåã®ãã£ã«ã¿ãŒã¬ã€ã€ãŒ
ç§ã¯ãã€ã³ã¿ãŒãã§ãŒã¹ãNLogã®ããã«äœæããããšã«ããŸããã éçã¯ã©ã¹LogAccessãšåŒã°ããã®ã¯ãäœããã®çç±ã§ãæå³ã®ç¹ã§ãããè«ççã«æããã 圌ã¯èªåã§äœãããããããã·ã®ã¿ãåŒã³åºããŸãã ãã®ããã圌ã¯ãã¹ãã«åå ããªããããããã§ã¯è©³ãã説æããŸããããå€éšãã«è¡šç€ºãããäž»èŠãªã¡ãœããã®ã¿ããªã¹ãããŸããæåã®ã¡ãœããã§ã¯ããã¬ãŒèªäœãã¹ãã ã¡ãã»ãŒãžã«ååŸã§ããŸãã æåã®ãã£ã«ã¿ãªã³ã°ã¬ã€ã€ãŒã«ãããã¬ãŒã®ååãŸãã¯ã«ããŽãªã¯ãåã®ã»ã¯ã·ã§ã³ã§èª¬æããã¯ã©ã¹ãééããåã«ãã®ãã£ã«ã¿ãªã³ã°ãå®è¡ãããããšãæå³ããŸããã€ãŸãããã°ã®ã«ããŽãªããšã«ã¬ãã«ãåå¥ã«èšå®ã§ããŸãã ããããã2çªç®ã®ãã£ã«ã¿ãŒã¬ã€ã€ãŒã«ã«ããŽãªãååšããªããšããããšã¯ããã®ãã£ã«ã¿ãŒããã¬ãŒã¹ããªãŒã ã§æ¢ã«è¡ãããŠããããšãæå³ããŸãã
Logger GetLogger(string category) void SetLevel(string category, int level) void SetLevelForAll(int level) void FilterAddID(int id) void FilterRemoveID(int id)
å€éšããèŠãã2çªç®ã®ã¯ã©ã¹ã¯LogLevelã§ãã ãã¬ã³ã ããåã£ãæå³ã®ã¬ãã«ã ãã®åŸãNLogãåçŽåããéåžžã®intãã¬ãã«ãšããŠäœ¿çšããŠãã¬ãã«ã®æ¯èŒãªã©ãè³¢ãããªãããšã«ããŸããã
圌ã¯ããã¹ãŠã®ã¬ãã«ã®ã¿ãè¿œå ããŠãççž®ãšè©³çŽ°ã®2ã€ã®ãããã°ã¬ãã«ãäœæããŸããããå®éã«ã¯äžè¶³ããŠããŸããã
public const int Invalid = 0; public const int Always = 1; public const int Fatal = 2; public const int Error = 3; public const int Warning = 4; public const int Info = 5; public const int Event = 6; public const int Debug = 7; public const int All = 8; public const int Total = 9;
LogAccessããã¬ãã«ãèšå®ããããã«ãã¯ã©ã¹ã«Defaultããããã£ãå«ããŸããã
æãéèŠãªããšã¯ãå€éšããèŠããã®ã¯Loggerã€ã³ã¿ãŒãã§ãŒã¹ã§ãã æå³çã«ãã¬ãã£ãã¯ã¹Iãè¿œå ããŸããã§ãããããã€ãã®ã¡ãœãããæäŸããŸãã
public interface Logger { /// <summary> /// Method for unrecoverable errors. /// </summary> /// <param name="message"></param> /// <param name="ex"></param> void Fatal(string message, Exception ex = null); /// <summary> /// Method for external errors, such as user input or file access. /// </summary> /// <param name="message"></param> /// <param name="id"></param> /// <param name="ex"></param> void Warning(string message, int id = 0, Exception ex = null); /// <summary> /// Method for regular debug logging. /// </summary> /// <param name="message"></param> /// <param name="id"></param> void Debug(string message, int id = null); }
ãšã©ãŒã®ã¡ãœããã¯èå¥åã«é¢é£ä»ããããŠããããèŠåã¬ãã«ä»¥äžã«ã®ã¿é¢é£ä»ããããŠããŸãã
次ã«ã衚瀺ããç¹å®ã®ãã¬ãŒã®ã¯ã©ã¹ãæ€èšããŸãã ãã¬ãŒãåŒã³åºãã¹ã¬ããããååŸããããã©ãŒãã³ã¹ã®å®éã®æå°åã¯ã©ã®ããã«éæãããŸããã ãšããã§ããã¬ãŒã€ã³ã¿ãŒãã§ã€ã¹ã«ã¯æ¡åŒµããŒãžã§ã³ããããå€éšããã¯èŠããªããããSetLevelã¡ãœãããè¿œå ãããŠããŸãã
class CheckingLogger : InternalLogger { bool[] levels = new bool[LogLevel.Total]; Sender send; string category; public CheckingLogger(string category, Sender sender, int level) { this.send = sender; this.category = category; SetLevel(level); } public void SetLevel(int level) { for (int n = LogLevel.Fatal; n < LogLevel.Total; n++) { levels[n] = (n <= level); } } public void Error(string message, Exception ex = null) { if (levels[LogLevel.Error]) { send(new LogItem(category, LogLevel.Error, message, ex: ex)); } }
1ã€ã®ã¹ãã éä¿¡æ¹æ³ãæ€èšããããã«ãé åããããŒã«å€ããã§ãã¯ãããããSenderããªã²ãŒãçµç±ã§éä¿¡ããããšã¯æããã§ãã ãã¬ãŒã®2çªç®ã®ããŒãžã§ã³ã§ã¯ãããŒã«é åã®ä»£ããã«éä¿¡è ã®é åã䜿çšããã空ã®ã¡ãœãããžã®ããªã²ãŒãããªãã¬ãã«ã«æ¿å ¥ãããéä¿¡ã¡ãœããã«ãã§ãã¯ããªããããã«éä¿¡ãããŸãã ãã¹ãçµæã«ãããšãããã©ãŒãã³ã¹ã®éãã¯ãããã§ãããããããç°ãªããã©ãããã©ãŒã ã§ãã¹ãããããšã§çããåŸãããŸãã ãã¬ãŒãã¹ãã¯éåžžã«ç°¡åã§ãã¡ãã»ãŒãžãéä¿¡è ã«éä¿¡ããããã©ãããéä¿¡ãã¹ãã¿ã€ãã³ã°ãšéä¿¡ãã¹ãã§ãªãã¿ã€ãã³ã°ã確èªããŸãã ãããããã¿ã€ããã¹ãã³ããŒã¢ã³ãããŒã¹ãã®ãšã©ãŒã«ãééããŸããã ã»ãšãã©åãã¡ãœããããããããããŸããããã®éãã¯äžèŠããã ãã§ã¯ããããŸããã
ã¯ã©ã¹ã«å ¥ãã»ã¯ã·ã§ã³ããŸãã¯å®éã«ãã°ãéä¿¡ããããã«äœ¿çšããLogItemæ§é ãèãåºãããšã¯ã§ããŸããã§ãããããã§ã¯ãã³ã³ã¹ãã©ã¯ã¿ãŒã¯çç¥ããã³ã³ãã³ãã®ã¿ãçç¥ããŸãã ã¡ãªã¿ã«ã1ã€ã®ã¡ãã»ãŒãžã®IDãè€æ°ã«èšå®ã§ããããšãããããŸããããã¯ããããŒããã£ã¹ãããŸãã¯åŒã³åºãã®å Žåã«ãçºä¿¡è ãšåŒã³åºãã«å¿çãã2ã€ã®èå¥åã瀺ãããã«å¿ èŠã§ãã åã®ã¯ã©ã¹ã®ã¡ãœããã¯ãã®ç®çã®ããã«è€è£œãããŠããã泚æã奪ãããŠããã ãã§ãã
struct LogItem { public readonly String category; public readonly String message; public readonly int[] ids; public readonly int level; public readonly Exception ex; public readonly DateTime time; }
äŸåæ§æ³šå ¥
ãã®ã»ã¯ã·ã§ã³ã§ã¯ãIoCã³ã³ãããŒã®äœ¿çšäŸã瀺ããŸãã 次ã®è¡ã¯ãã¬ãŒã®ã¯ã©ã¹ã§ãã ååã¯IoCã³ã³ããã«é¢é£ä»ããããŠããããäžèŽããã ãã§ãã LogAccessã¯ã©ã¹ã¡ãœããããããã·ãããGetLoggerã¡ãœãããæäŸããŸãã NLogã¯ãã³ãŒãå ã®ã³ã¡ã³ãããå€æãããšãåãã«ããŽãªã§2ååŒã³åºãããGetLoggerã¡ãœãããåããã¬ãŒã€ã³ã¹ã¿ã³ã¹ãäžããããšãä¿èšŒããŸããã ç§ã¯ãã®æ¹æ³ãããã«ããã¯ã«ãªããªãããšãèãã決å®ããäžè¬çãªåæãèšå®ããŸããããã®å Žåãã€ã³ã¹ã¿ã³ã¹ã¯åããã®ãä¿èšŒããå¿ èŠããããŸãã ãã°ã³ã³ããã¯ã以åã«äœæããããã¹ãŠã®ãã¬ãŒãä¿åããLogAccessãããããã·ãããSetLevelãé åžããŸãã
ãã®ãããIoCã³ã³ãããŒãäœæãã次ã®2è¡ã®éã«ããã«æ§æãé 眮ããŸãã
var builder = new ContainerBuilder(); IContainer container = builder.Build();
äžèšãããã¯ã©ã¹ãã·ã³ã°ã«ãã³ã§ãªããã°ãªããªãããšã¯æããã§ãã ããã¯éåžžã«ç°¡åã«å®çŸã§ããŸãã
builder .RegisterType<LoggerContainer>() .SingleInstance();
次ã®æ¹æ³ã§ã¯ãã·ã³ã°ã«ãã³ãžã®ãªã³ã¯ãååŸã§ããŸãã
Container .Resolve<LoggerContainer>();
ãã°ã³ã³ãããŒèªäœãäœæå ã®IoCã³ã³ãããŒã®ãµãŒãã¹ã䜿çšã§ããããã«ãã³ã³ã¹ãã©ã¯ã¿ãŒã§IComponentContextãã©ã¡ãŒã¿ãŒãè¿œå ããŸããã ããã«ãããã¯ã©ã¹ã®äœæãå€éšã«æã¡ãç¹å®ã®ã¯ã©ã¹ããããšãã°ã䜿çšããã³ãŒããå€æŽããã«ãæ©èœãæ¡åŒµããã¯ã©ã¹ã«å€æŽã§ããŸãããæ§æãå€æŽããã ãã§ãã ã³ãŒãã«èšå®ããã®ã§ã¯ãªããxmlããèªã¿èŸŒãããšãã§ããŸãã å®éããã®å éšäœæããå€éšäœæãžã®çœ®ãæãã¯ãäŸåé¢ä¿ã®å®è£ ãšåŒã°ããŸãã å®éã«ã¯ãã³ã³ããã¹ãããç¹å®ã®ãã¬ãŒãåãåãã¡ãœããïŒ
private InternalLogger CreateLogger(string category) { return context .Resolve<InternalLogger>(new NamedParameter[]{ new NamedParameter("category", category), new NamedParameter("level",LogLevel.Default) }); }
, , , , , . , , .
builder .RegisterType<CheckingLogger>() .As<InternalLogger>();
, , , . , , , . , , . «» .
, IoC: -. :
[TestClass()] public class LoggerContainerTest { IContainer testContainer; public LoggerContainerTest() { var builder = new ContainerBuilder(); builder .Register<LoggerContainer>((c, p) => new LoggerContainer(c.Resolve<IComponentContext>())); builder .RegisterType<LoggerMock>() .As<InternalLogger>(); testContainer = builder.Build(); }
, Autofac, new, Resolve, , , , .
.
LoggerContainer lc= testContainer .Resolve<LoggerContainer>(); var logger1 = lc.GetLogger(cat1); var logger2 = lc.GetLogger(cat2); var logger3 = lc.GetLogger(cat1); Assert.AreEqual(logger1, logger3); Assert.AreNotEqual(logger1, logger2);
Moq
, . , LogCollector-. IQueued , , .
, , , , LogItem. , .
NLog: layout="${longdate} ${uppercase:${level}} ${message}".
LogMessageFormat=\d \l \m\r\n.
, , , . , . , , . , StringBuilder LogItem . , .
, , , . , , , . â , HashSet, . , , . Action . filterQue = new ConcurrentQueue<Action<HashSet>>();
, , , , .
Action<HashSet<int>> refresh; while (!filterQue.IsEmpty) { if (filterQue.TryDequeue(out refresh) && refresh != null) { refresh(filter); } }
, , .
filterQue.Enqueue((x)=> { x.Add(id); });
Moq â , , , , . Moq , . â . , GoF, « », , , - , , , , .
Moq â , , internal , , , Moq , , . AssemblyInfo.cs , , :
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("LoggerTest"), System.Runtime.CompilerServices.InternalsVisibleTo("DynamicProxyGenAssembly2")]
, , , .
, -, , , .
LogItem message = new LogItem(category, level, msg, ids, GetException()); var qThread = new Mock<IQueued<LogItem>>(MockBehavior.Strict); var writer = new Mock<ILogWriter>(MockBehavior.Strict); qThread .Setup(s => s.Send(It.IsAny<LogItem>())); writer .Setup(s => s.GetTimeout()) .Returns(timeout); qThread .Setup(s => s.SetTimeout(It.IsAny<int>())); LogCollector target = new LogCollector(qThread.Object, writer.Object); qThread .Verify(s => s.SetTimeout(It.Is<int>(a => a == timeout))); target.Send(message); qThread .Verify(s => s.Send(It.Is<LogItem>(i => i.Equals(message))), Times.Once()); }
, : . Strict , , , , .
Send IQueued , , . , , VerifyAll(). , . , GetTimeout, , . SetTimeout.
, , , GetTimeout . , , , . , , .
, , , , Moq.
è² è·è©Šéš
NLog, , , . , .
.
var log = SharpLogger.LogAccess.GetLogger("flooder " + tid); foreach (var x in Enumerable.Range(0, messageCount)) { log.Info("Message", x); if (x % 1000 == 0) Thread.Sleep(0); }
NLog.
var log = NLog.LogManager.GetLogger("flooder " + tid); foreach (var x in Enumerable.Range(0, messageCount)) { log.Info("Message"); if (x % 1000 == 0) Thread.Sleep(0); }
tid, , .
, , , , . 200 . . â , , 5 â NLog. , .
.
x64 .
â , Nlog, , , , , . , 40 , .
, â 7.15 ., , 25 . , , , , , NLog , , , . , NLog , .
, â .
, 3 15 , 22.2 17.8. 30, , 1.5 , 23.7 , 17.4, .
, 4 i5 4, windows 8.
https://github.com/repinvv/SharpLogger
, â .