![](https://habrastorage.org/storage2/a2c/dfb/eeb/a2cdfbeeb6e8dc07ae3831377fcab493.png)
åé¡ã®å£°æ
ãã®ãããè€æ°ã®ã¹ã¯ãªãããéåæã«ããŸãã¯ç¹å®ã®ã¹ã¬ããã§å®è¡ããæ©äŒã欲ããã§ãã ãããè¡ãã«ã¯ã次ã®ã¿ã¹ã¯ãæ åœããç¹å®ã®ãµãŒãã¹ãå¿ èŠã§ãã
- ã¹ã¯ãªããã䜿çšããŠäœæ¥ã¿ã¹ã¯ãžã®ãªã³ã¯ãä¿åãã
- ç¹å®ã®ã¹ã¯ãªããã¿ã¹ã¯ãåæ¢ããèŠæ±
- ã¿ã¹ã¯ã¹ããŒã¿ã¹ã®è¿œè·¡
- ã³ã³ãœãŒã«ãžã®ãã°åºåïŒStdoutããã³StderrïŒ
- ãããŒããã£ã¹ãã€ãã³ãã«ããã³ã³ãœãŒã«ãžã®ããã¹ãåºåã®éç¥
äžè¬çã«ããã®ãããªãã®
![](https://habrastorage.org/storage2/fc9/30c/eaf/fc930ceaf78618836b5543f166fa9189.png)
ããã«ã¯äœãæãããŠããŸããïŒ ã«ãŒãããŒã-" IRE.Instance "-ã¯ãã¹ã¯ãªããã®åäœã調æŽãããµãŒãã¹ãã®ãã®ã®åœ¹å²ãæããã·ã³ã°ã«ãã³ã§ãã ãããè¡ãããã«ãèŸæžã¯ã·ã³ã°ã«ãã³ã€ã³ã¹ã¿ã³ã¹ã«æ ŒçŽãããåã¿ã¹ã¯ã®ãšã³ããªã¯RunScriptWithSchedulerããã³RunScriptAsyncé¢æ°ãä»ããŠè¿œå ãããŸã ã ååã瀺ãããã«ããããã®æ©èœã¯ã¹ã±ãžã¥ãŒã©ã«ãã£ãŠç°ãªãããã®å¶åŸ¡äžã§ã¿ã¹ã¯ãèµ·åãããŸãã ãRunScriptWithSchedulerãã䜿çšãããšãããšãã°GUIã¹ã¬ããã§ã¿ã¹ã¯ãå®è¡ã§ããŸãã " WriteMessage "ããã³ " WriteError " ã¡ãœããã¯ã©ãããã§ãïŒã¹ã¯ãªãããå«ãïŒå©çšã§ããã¡ãã»ãŒãžãã°ãžã®åºåãç®çãšããŠããŸãã ã¹ã¯ãªããã®åŽã§ã¯ãããã¹ãããµãŒãã¹ãã°ã«ãªãã€ã¬ã¯ãããããã«ãã³ã³ãœãŒã«ãžã®æšæºåºåã¡ãœããããªãŒããŒã©ã€ãã§ããŸãã
ãµãŒãã¹ã¿ã¹ã¯ãã£ã¯ã·ã§ããªã®ãšã³ããªã¯äœã«ãªããŸããïŒ ããŒã¯ãå®è¡äžã®ã¹ã¯ãªãããèå¥ããäžæã®GUIDã§ãã ãã®GUIDã¯ãã¹ã¯ãªããã®å®è¡ãèŠæ±ããããŒãã£ã«ç°¡åã«è»¢éã§ããã¹ã¯ãªããèªäœã®ã³ã³ããã¹ãã«åã蟌ãããšãã§ããŸãã ã¬ã³ãŒãå€ã«ã¯ãå°ãªããšãCancelationToukenSourceããã³Taskãžã®åç §ãæ ŒçŽããå¿ èŠããããŸãã Taskã¹ã¯ãªããã®äœæã«äœ¿çšãããCancelationToukenSourceã䜿çšãããšããã€ã§ãçµäºããå¿ èŠãããããšãã¿ã¹ã¯ã«éç¥ã§ããŸãã ã¿ã¹ã¯èªäœãžã®ãªã³ã¯ã«ãããContinuationãç¶ç¶ã§ããŸãïŒããã§ã¯TPLã«ã€ããŠè©³ãã説æããŸããïŒã
IREãµãŒãã¹
ããããããšã³ãžã³ã®ã³ã¢ãã€ãŸãã·ã³ã°ã«ãã³ã®åœ¢åŒã§äœæããããµãŒãã¹ã®èª¬æããå§ããŸãããã ã·ã³ã°ã«ãã³å®è£ ã¯ã MSDNããååŸãããŸã ã ãŸããJAVAã®ããŸããŸãªã·ã³ã°ã«ãã³å®è£ ã®ããªã詳现ãªåæãžã®ãªã³ã¯ããããŸãã ãŸã èªãã§ããªã人ã¯èªãããšã匷ããå§ãããŸãã
ãã®ããããµãŒãã¹ããã«ãã¹ã¬ããã®ãããã«ãã§ãã¯ããã¯ãã·ã³ã°ã«ãã³ãšããŠå®è£ ããŸããã åºæ¬å®è£ ã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
ã·ã³ã°ã«ãã³ã³ã¡ã³ãã³ãŒã
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using IronRuby; using Microsoft.Scripting; using Microsoft.Scripting.Hosting; using System.IO; using System.Threading.Tasks; using System.Diagnostics; using Microsoft.Scripting.Runtime; namespace IREngine { public sealed class IRE { #region Singleton private static volatile IRE _instance; private static readonly object SyncRoot = new Object(); private IRE() { // // IRE.Instance // , - ( , ) // var instance = IRE.Instance; } public static IRE Instance { get { if (_instance == null) { lock (SyncRoot) { if (_instance == null) _instance = new IRE(); } } return _instance; } } #endregion #region Consts // #endregion #region Fields // #endregion #region Properties // #endregion #region Private Methods // #endregion #region Public Methods // #endregion } }
æ§é ã¯ã³ã¡ã³ãããæããã ãšæããŸãã ã³ãŒãã§èª¬æããç¹å¥ãªãã®ã¯ãããŸããã åºæ¬çã«ã·ã³ã°ã«ãã³ã®ã³ã¡ã³ãã2ã3ã ãä»ããŸãã ã·ã³ã°ã«ãã³ã®ä»£ããã«ãéçãã«ããŒã䜿çšã§ããŸãã ããããã·ã³ã°ã«ãã³ã©ã€ããµã€ã¯ã«ã¯å¶åŸ¡ã容æã§ãã ããšãã°ãéçã³ã³ã¹ãã©ã¯ã¿ãŒã®åŒã³åºãã®ç¬éã¯é決å®çã§ãããééçã³ã³ã¹ãã©ã¯ã¿ãŒã®åŒã³åºãã¯ã€ã³ã¹ã¿ã³ã¹ãžã®æåã®ã¢ã¯ã»ã¹ã§ã®ã¿çºçããŸãã ããã«ãããã·ã³ã°ã«ãã³ãéå§ããåã«å°æ¥äœããåæåããå¿ èŠãããå Žåãæ¯èŒçå®å šã«æããããšãã§ããŸãã ãã1ã€ã®èå³æ·±ãç¹ã¯ããnullãã®äºéãã§ãã¯ã§ãã 2ã€ã®ã¹ã¬ããã¯åæã«æåã®æ¡ä»¶å ã«ååšã§ããŸããããããã¯ãã¯ãã®ãã¡ã®1ã€ã ãã§å®è¡ãããŸãã 2çªç®ã®ã¹ã¬ããã¯ãæåã®ã¹ã¬ãããã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ãçµäºãããŸã§åŸ æ©ããŸãã ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã解æŸããåŸã2çªç®ã®ã¹ã¬ããã¯ã€ã³ã¹ã¿ã³ã¹ã®ãnullããå床ãã§ãã¯ããå¿ èŠããããŸãã ãããã£ãŠã䞊åå®è¡ã¹ã¬ããã§ã·ã³ã°ã«ãã³ã®2ã€ã®ã€ã³ã¹ã¿ã³ã¹ãäœæããç¶æ³ã¯èš±å¯ãããŸããã
TPLã®äœ¿çšã«ã€ããŠç°¡åã«
次ã«ãTPLã®åºæ¬ã«ã€ããŠç°¡åã«èª¬æããŸãã CodeProjectã§è©³çŽ°ãèªãããšãã§ããŸãã
æåã«äœæããéåæã¿ã¹ã¯ã¯ãã³ã³ãœãŒã«åºåãããã¡ãŒã®ç£èŠã§ãã æåã«æžããããã«ããµãŒãã¹ã®æ©èœã®1ã€ã¯ãã³ã³ãœãŒã«ãžã®ã¡ãã»ãŒãžãšãšã©ãŒã®ãã®ã³ã°ã§ãã ããã§ãäœãå¿ èŠã§ããïŒ
- åºåãããã¡ã®å€æŽããã§ãã¯ããã¢ã¯ã·ã§ã³
- åºåãããã¡ããã§ãã¯ãããšãã®ã¢ã¯ã·ã§ã³ãšã©ãŒåŠç
- ãšã©ãŒãããã¡ã®å€æŽã確èªããã¢ã¯ã·ã§ã³
- ãšã©ãŒãããã¡ããã§ãã¯ãããšãã®ã¢ã¯ã·ã§ã³ãšã©ãŒåŠç
- ã¢ã¯ã·ã§ã³ãå®è¡ããããã®ã¿ã¹ã¯ã€ã³ã¹ã¿ã³ã¹ãäœæãããããªãã¯ã¡ãœãã
ã·ã³ã°ã«ãã³ã®ãã©ã€ããŒãã³ã³ã¹ãã©ã¯ã¿ãŒã«ã¢ã¯ã·ã§ã³ã®åæåãé 眮ããŸããã
åæåã¢ã¯ã·ã§ã³
private IRE() { // Ruby _outStringBuilder = new StringBuilder(); _errStringBuilder = new StringBuilder(); _outWatchAction = () => { int i = 0; while (IsConsoleOutputWatchingEnabled) { string msg = string.Format("***\t_outWatchTask >> tick ({0})\t***", i++); Debug.WriteLine(msg); WriteMessage(msg); Task.Factory.CancellationToken.ThrowIfCancellationRequested(); int currentLength = OutputBuilder.Length; if (OutputUpdated != null && currentLength != _lastOutSize) { OutputUpdated.Invoke(_outWatchTask, new StringEventArgs(OutputBuilder. ToString(_lastOutSize, currentLength - _lastOutSize))); _lastOutSize = currentLength; } Thread.Sleep(TIME_BETWEEN_CONSOLE_OUTPUT_UPDATES); } }; _outWatchExcHandler = (t) => { if (t.Exception == null) return; Instance.WriteError( string.Format( "!!!\tException raised in Output Watch Task\t!!!\n{0}", t.Exception.InnerException.Message)); }; _errWatchAction = () => { int i = 0; while (IsConsoleErrorWatchingEnabled) { string msg = string.Format("***\t_errWatchTask >> tick ({0})\t***", i++); Debug.WriteLine(msg); WriteError(msg); Task.Factory.CancellationToken.ThrowIfCancellationRequested(); int currentLength = ErrorBuilder.Length; if (ErrorUpdated != null && currentLength != _lastErrSize) { ErrorUpdated.Invoke(_errWatchTask, new StringEventArgs(ErrorBuilder. ToString(_lastErrSize, currentLength - _lastErrSize))); _lastErrSize = currentLength; } Thread.Sleep(TIME_BETWEEN_CONSOLE_OUTPUT_UPDATES); } }; _errWatchExcHandler = (t) => { if (t.Exception == null) return; Instance.WriteError( string.Format( "!!!\tException raised in Error Watch Task\t!!!{0}", t.Exception.InnerException.Message)); }; }
以äžã¯ãå¿ èŠãªããããã£ãå®æ°ãããã³ãã©ã€ããŒããã£ãŒã«ãã®å®£èšã§ãã
ãã£ãŒã«ããããããã£ãå®æ°ã®åæå
#region Consts public readonly int TIME_BETWEEN_CONSOLE_OUTPUT_UPDATES = 1000; #endregion #region Fields private bool _outWatchEnabled; private bool _errWatchEnabled; private Task _outWatchTask; private readonly CancellationTokenSource _outWatchTaskToken = new CancellationTokenSource(); private int _lastOutSize = 0; private Task _errWatchTask; private readonly CancellationTokenSource _errWatchTaskToken = new CancellationTokenSource(); private int _lastErrSize = 0; private readonly StringBuilder _outStringBuilder; private readonly StringBuilder _errStringBuilder; private readonly Action _outWatchAction; private readonly Action<Task> _outWatchExcHandler; private readonly Action _errWatchAction; private readonly Action<Task> _errWatchExcHandler; private readonly CancellationTokenSource _scriptsToken = new CancellationTokenSource(); #endregion #region Properties public StringBuilder OutputBuilder { get { lock (SyncRoot) { return _outStringBuilder; } } } public StringBuilder ErrorBuilder { get { lock (SyncRoot) { return _errStringBuilder; } } } public bool IsConsoleOutputWatchingEnabled { get { lock (SyncRoot) { return _outWatchEnabled; } } set { lock (SyncRoot) { _outWatchEnabled = value; } } } public bool IsConsoleErrorWatchingEnabled { get { lock (SyncRoot) { return _errWatchEnabled; } } set { lock (SyncRoot) { _errWatchEnabled = value; } } } public event EventHandler<StringEventArgs> OutputUpdated; public event EventHandler<StringEventArgs> ErrorUpdated; #endregion
ãã®ã³ãŒãã¯äœãããŸããïŒ å®æçã«ãStringBuilderã®é·ããæ¯èŒãããé·ããå€æŽããããšã察å¿ããã€ãã³ãããã«ãããŸãã ãã®ã€ãã³ãã®ãã³ãã©ãŒïŒGUIåŽïŒã¯ãè¿œå ãããã¡ãã»ãŒãžããã¹ãã衚瀺ããŸãã GUIåŽã§ã¯ããã³ãã©å ã®ã³ãŒããã¿ã¹ã¯å ã§å®è¡ãããŸãããGUIããåä¿¡ããã¿ã¹ã¯ã¹ã±ãžã¥ãŒã©ã®æ瀺çãªæ瀺ãããããšã«æ³šæããŠãã ããã ãªããªã GUIã¹ã¬ããã§å®è¡ãããªãéåæã¿ã¹ã¯ã§ã¯ã€ãã³ãããŽããŽãåãããããã³ãã©ãŒã®ã³ãŒãã¯ã€ã³ã¿ãŒãã§ãŒã¹èŠçŽ ã«çŽæ¥ã¢ã¯ã»ã¹ã§ããŸããã ã¡ã€ã³ã¢ããªã±ãŒã·ã§ã³ãŠã£ã³ããŠã®ã¹ã±ãžã¥ãŒã©ãæ瀺çã«æå®ããŠãã¢ã¯ã·ã§ã³ãäœæããã€ã³ã¿ãŒãã§ã€ã¹ã¹ã¬ããã§å®è¡ããå¿ èŠããããŸãã 以äžã¯ãGUIåŽã®ã€ãã³ããã³ãã©ãŒã®ã³ãŒãã§ãã
ã€ãã³ããã³ãã©ãŒã³ãŒã
IRE.Instance.OutputUpdated += (s, args) => { string msg = string.Format("***\tIRE >> Out Updated callback\t***\nResult: {0}\n***\tEND\t***\n",args.Data); Debug.WriteLine(msg); var uiUpdateTask = Task.Factory.StartNew(() => { OutputLogList.Items.Add(msg); }, Task.Factory.CancellationToken, TaskCreationOptions.None, _uiScheduler); uiUpdateTask.Wait(); }; IRE.Instance.ErrorUpdated += (s, args) => { string msg = string.Format("!!!\tIRE >> Err Updated callback\t!!!\nResult: {0}\n!!!\tEND\t!!!\n", args.Data); Debug.WriteLine(msg); var uiUpdateTask = Task.Factory.StartNew(() => { ErrorLogList.Items.Add(msg); }, Task.Factory.CancellationToken, TaskCreationOptions.None, _uiScheduler); uiUpdateTask.Wait(); }; IRE.Instance.StartWatching();
ãã®ã³ãŒãã¯ãã³ã³ãœãŒã«åºåãããã¡ãŒã®æŽæ°ã€ãã³ãã«ãµãã¹ã¯ãªãã·ã§ã³ãè¿œå ããŸãã ãã®äžã§æ³šç®ãã¹ãäž»ãªãã®ã¯ã _uiScheduler ãã§ãã ããã¯ãã¡ã€ã³ãŠã£ã³ããŠã®ãã¶ã€ããŒã§äœæãããïŒãŠã£ã³ããŠïŒã¹ã±ãžã¥ãŒã©ãŒãžã®ãªã³ã¯ã§ãã ãã®ãªã³ã¯ã¯æ¬¡ã®ããã«äœæãããŸãã
public MainWindow() { InitializeComponent(); _uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); }
ãã®ã¹ã±ãžã¥ãŒã©ã§äœæããããã¹ãŠã®ã¿ã¹ã¯ã¯ãã€ã³ã¹ããŒã«ãããŠããã¹ã¬ããã«é¢ä¿ãªããGUIã¹ã¬ããã§èµ·åãããŸãã ã°ã©ãã£ã«ã«ã€ã³ã¿ãŒãã§ã€ã¹èŠçŽ ãžã®ç絡ã¯ãã¯ãã¹ã¹ã¬ããã¢ã¯ã»ã¹äŸå€ãåŒãèµ·ãããŸããã
ã uiUpdateTask.WaitïŒïŒ; ããšããè¡ã«ã€ããŠã " try-catch "ã§ãã®è¡ããã¬ãŒã åããããšãæãŸããã§ãã ã¿ã¹ã¯å ã§çºçãããã¹ãŠã®äŸå€ã¯ãã¿ã¹ã¯ãäœæããã¹ã¬ããã«ããã«ã¯è»¢éãããŸããã åŒã³åºãã¹ã¬ããã§äŸå€ã«ã¢ã¯ã»ã¹ãã1ã€ã®æ¹æ³ã¯ãWaitïŒïŒé¢æ°ãåŒã³åºãããšã§ãã ã¿ã¹ã¯ã«ãç¶ç¶ããè¿œå ããŠããã®äžã«äŸå€ãæçš¿ããããšãã§ããŸãã æ¹æ³ã¯é¢ä¿ãããŸããããäŸå€ãåŠçããå¿ èŠããããŸãã ãã以å€ã®å ŽåããGarbageCollectorããã¿ã¹ã¯ã«å°éãããšãäŸå€ãåŒã³åºãã¹ã¬ããã«éä¿¡ãããŸãã ã©ã®æç¹ã§ãããèµ·ãããã¯äžæã§ãã ãããã£ãŠãã¢ããªã±ãŒã·ã§ã³ã«ãšã£ãŠããã¯èŽåœçã§ãã
ãã®å Žåãç°¡åã«ããããã«ãã try-catch ãã¯è¿œå ããŸããã§ããããããããåŸã§è¿œå ããŸãã ããã§ã®ã³ãŒãã¯éåžžã«åçŽã§ãããå°æ¥ã¯ãã¹ãŠãå€æŽãããå¯èœæ§ããããŸãã
ã³ã³ãœãŒã«åºåãç£èŠããããã®ã¿ã¹ã¯ãäœæããããã®ã³ãŒããæäŸããããšã¯æ®ããŸãã
public void StartWatching() { StopWatching(); if (_outWatchTask != null) _outWatchTask.Wait(); if (_errWatchTask != null) _errWatchTask.Wait(); IsConsoleOutputWatchingEnabled = IsConsoleErrorWatchingEnabled = true; _outWatchTask = Task.Factory.StartNew(_outWatchAction, _outWatchTaskToken.Token); _outWatchTask.ContinueWith(_outWatchExcHandler, TaskContinuationOptions.OnlyOnFaulted); _errWatchTask = Task.Factory.StartNew(_errWatchAction, _errWatchTaskToken.Token); _errWatchTask.ContinueWith(_errWatchExcHandler, TaskContinuationOptions.OnlyOnFaulted); }
ããã®ãã¹ãŠãç°¡åã§ãã 念ã®ããã远跡ã¿ã¹ã¯ãåæ¢ããŸãïŒ " StopWatchingïŒïŒ; "ïŒã ãã®é¢æ°ãåŒã³åºããšãåçŽã«ã IsConsoleOutputWatchingEnabled ãããã³ã IsConsoleErrorWatchingEnabled ã ãã©ã°ã falseã«èšå®ããã ã CancelationToken ãã®ãã¬ãŒã¯ãåæ¢ãããŸãã ããŒã¯ã³ã ãã«å¶éããããšãã§ããŸãã ãã ããäžè¬ã«ãããŒã¯ã³ãä»ããåæ¢èŠæ±ã¯ç·æ¥åæ¢ãšèŠãªãããŸãã ç¹å¥ãªé¢æ° " Task.Factory.CancellationToken.ThrowIfCancellationRequestedïŒïŒ; "ããããŸãããã®é¢æ°ã®åŒã³åºãã«ãããããŒã¯ã³ãä»ããã¿ã¹ã¯ã®å®è¡äžã«ãã£ã³ã»ã«èŠæ±ãåä¿¡ãããå Žåãã¿ã¹ã¯ã¯äŸå€ãã¹ããŒããŸãã ãã®é¢æ°ãåŒã³åºããŠãäžè¬ã«CancelationTokenã®ã¹ããŒã¿ã¹ã確èªããã®ã¯éåžžã«ã³ã¹ãã®ãããæé ã§ãã ãããã£ãŠãã§ããéããã£ãã«è¡ããªãããšãæãŸããã
次ã«æ³šæãããã®ã¯ãã _outWatchTask.ContinueWithïŒ_outWatchExcHandlerãTaskContinuationOptions.OnlyOnFaultedïŒ; ããšãã圢åŒã®æ§ç¯ã§ãã ãã®ã³ãŒãã¯ããããããç¶ç¶ãïŒç¶ç¶ïŒãšããã¿ã¹ã¯ã«ãã³ã°ã¢ããããŸãã ããã«ããªãã·ã§ã³ã TaskContinuationOptions.OnlyOnFaulted ãã§ç¶ç¶ãäœæãããŸãã ãã®ãããªç¶ç¶ã¯ãã¿ã¹ã¯ã®ãAggregatedExceptionãã«å°ãªããšã1ã€ã®äŸå€ãå«ãŸããŠããå Žåã«ã®ã¿åŒã³åºãããŸãã ç°¡åã«èšãã°ãã¿ã¹ã¯ãæ£åžžã«å®äºããå Žåããã®ç¶ç·šã¯ç¡èŠãããŸãã ãŸããããã€ãã®äŸå€ãååšããå¯èœæ§ãããããšã«ã泚æããŠãã ããã çµå±ããã®ã¿ã¹ã¯å ã«ãã¹ãããããµãã¿ã¹ã¯ãäœæã§ããŸãã ãã¹ããããã¿ã¹ã¯ãã GC ãã«ãã£ãŠåéããããšãæªåŠçã®äŸå€ã¯ãã¹ãŠãåããAggregatedExceptionãã®åœ¢åŒã§èŠªã«ãããã¢ããããŸãã ãããã£ãŠããã¹ããããäŸå€ã®ããªãŒå šäœãååŸã§ããŸãã ãã®äŸå€ããªãŒããã©ãããªã¹ãã«å€æããç¹å¥ãªã¡ãœããã AggregatedException.FlattenïŒïŒ ãããããŸãã
ã¹ã¯ãªããã®åºæ¬
ããã§ã¯ãã¹ã¯ãªããèªäœã«ã€ããŠè©±ããŸãããã ãŸãããScriptEngineããäœæããã¢ããªã±ãŒã·ã§ã³ã«å¿ èŠãª.Netã¢ã»ã³ããªãããŒãããå¿ èŠããããŸãã ããã¯åçŽã«è¡ãããŸãïŒ
_defaultEngine = Ruby.CreateEngine((setup) => { setup.ExceptionDetail = true; }); _defaultEngine.Runtime.LoadAssembly(typeof(IRE).Assembly);
ãã®ã³ãŒããã·ã³ã°ã«ãã³ãã©ã€ããŒãã³ã³ã¹ãã©ã¯ã¿ãŒã®äžéšã«è¿œå ããŸããã ã³ãŒãã®æåã®éšåã¯ãå®éã«ScriptEngineã®ã€ã³ã¹ã¿ã³ã¹ãäœæããŸãã ãã©ã¡ãŒã¿ãŒãšããŠæž¡ãããã©ã ãã䜿çšãããšããšã³ãžã³ãæ§æã§ããŸãã ããã¯ãªãã·ã§ã³ã§ãã ãããããã®ã¢ãããŒãã§ã¯ãScriptEngineãRubyã³ãŒããã³ã³ãã€ã«ããªãããã«ããŠãã¹ã¯ãªãããæ¯å解éãããããã«ããããšãã§ããŸãã ããã¯ãããšãã°ãWindowsPhone 7ãã©ãããã©ãŒã ã§äŸ¿å©ã§ãã ã¡ã¢ãªãç¯çŽããŸãã äŸå€ã«é¢ããæ å ±ã®è©³çŽ°ãªåºåãå«ããŸããã
2çªç®ã®éšåã¯ããµãŒãã¹ãå«ãã¢ã»ã³ããªãRubyãšã³ãžã³ã®ã©ã³ã¿ã€ã ã«åçŽã«ããŒãããŸãã ããããªããšãã¹ã¯ãªããããã¢ããªã±ãŒã·ã§ã³ãšéä¿¡ã§ããªããªããŸãã åæ§ã«ãä»ã®å¿ èŠãªã¢ã»ã³ããªãããŒãã§ããŸãã äžè¬ã«ããã®ã¢ã»ã³ããªã®èªã¿èŸŒã¿ãå¥ã®æ¹æ³ã§è¡ãããšããå§ãããŸããããã«ãããæ°ããã¢ã»ã³ããªãç°¡åã«è¿œå ã§ããåæã«åãçš®é¡ã®ã³ãŒãè¡ã®ã·ãŒããç®éãã«ãªããŸããã
éåæã¿ã¹ã¯ã¹ã¯ãªãããšããã€ãã®ãµãŒãã¹ã¡ãœãããè¿œå ããé¢æ°ã®ã³ãŒããæäŸããããšã¯æ®ã£ãŠããŸãã
éåæã³ãŒãã¿ã¹ã¯ã¹ã¯ãªããã®è¿œå
public Guid RunScriptAsync(string code) { var scriptScope = _defaultEngine.CreateScope(); CompiledCode compiledCode = null; try { ScriptSource scriptSource = _defaultEngine.CreateScriptSourceFromString(code, SourceCodeKind.AutoDetect); var errListner = new ErrorSinkProxyListener(ErrorSink.Default); compiledCode = scriptSource.Compile(errListner); } catch (Exception ex) { WriteError(ex.Message); return Guid.Empty; } var action = new Action(() => compiledCode.Execute(scriptScope)); var tokenSource = new CancellationTokenSource(); var task = new Task(action, tokenSource.Token, TaskCreationOptions.LongRunning); var guid = Guid.NewGuid(); AddTask(guid, new TaskRecord { TokenSource = tokenSource, Task = task }); task.Start(); task.ContinueWith((t) => { // Actually we don't needed this due to "TaskContinuationOptions.OnlyOnFaulted" is set if (t.Exception == null) return; t.Exception.Flatten().Handle((ex) => { Instance.WriteError(t.Exception.InnerException.Message); return true; }); }, TaskContinuationOptions.OnlyOnFaulted); task.ContinueWith((t) => { Instance.RemoveTask(guid); }); return guid; } public void AddTask(Guid key, TaskRecord record) { _tasks.Add(key, record); } public void RemoveTask(Guid key) { _tasks.Remove(key); } public Task GetTask(Guid key) { return _tasks.ContainsKey(key) ? _tasks[key].Task : null; } public void RequestCancelation(Guid key) { var tokenSource = _tasks.ContainsKey(key) ? _tasks[key].TokenSource : null; if (tokenSource == null) return; tokenSource.Cancel(); }
ããã«ã¯äœããããŸããïŒ ãŸããScriptScopeãäœæããŸãã ããã©ã«ãã®Rubyãšã³ãžã³ã䜿çšããŸãããåScriptScopeã«ã¯ç¬èªã®ã¹ã¯ãªããããããŸãã ãã¹ãŠã®å€æ°ãšã¹ã¯ãªããå®è¡çµæã®ã¹ã³ãŒãã¯ããããã®ã¹ã³ãŒãã«å¶éãããŸãã
ããã«ãtry-catchãã®å éšã§ScriptSourceãšCompiledCodeãäœæãããŸãã ããã©ã€-ãã£ããããå¿ èŠã§ã ã³ã³ãã€ã«æžã¿ã³ãŒãã®äœææã«äŸå€ãçºçããå ŽåããããŸãã ãã®å Žåã空ã®Guidãè¿ããåŒã³åºãåŽã¯ãã®ç¶æ³ãé©åã«åŠçããå¿ èŠããããŸãã ã¹ã¯ãªãããæ£åžžã«ã³ã³ãã€ã«ãããããã¹ã¯ãªããå®è¡ã¿ã¹ã¯ã®äœæãéå§ã§ããŸãã
ãããã£ãŠãã¹ã¯ãªãããå®è¡ããã¢ã¯ã·ã§ã³ãäœæããCancelationTokenSourceããªãã·ã§ã³ãTaskCreationOptions.LongRunningããæã€æ°ããã¿ã¹ã¯ãäœæããŸãïŒçµå±ãã¹ã¯ãªããã¯é·æéå®è¡ãããå¯èœæ§ããããŸãïŒã 次ã«ãã¿ã¹ã¯ã®æ°ããGUIDãäœæããæåŸã«ããã¹ãŠãã¹ã¯ãªããåãããã¿ã¹ã¯ã®èŸæžã®æ°ãããšã³ããªã«ããã¯ããŸãã æåã«èšç»ãããšããã
äœæåŸãã¿ã¹ã¯ãå®è¡ããäŸå€åŠçã䜿çšããŠã¿ã¹ã¯ã«ç¶ç¶ãæ·»ä»ããŸãã ã¿ã¹ã¯ã®ç¶ç¶ã§ã¯ããšã©ãŒã¡ãã»ãŒãžããã°ã«æžã蟌ãã åŸãAggregatedExceptionãããã©ããåããããã¹ãŠã®äŸå€ãåŠçããŸãïŒ trueãè¿ããŸã ïŒã
äžèšã®ç¶ç¶ã«å ããŠãã¿ã¹ã¯ã®å®äºæã«åŒã³åºãããå¥ã®ç¶ç¶ãæ·»ä»ããŸãã ãã®ç¶ãã§ã¯ã䜿çšæžã¿ã®TaskãèŸæžããåé€ããŸãã ãã¯ãæçšã§ã¯ãããŸããã
ãµãŒãã¹æ©èœã䜿çšãããšããã¹ãŠãã·ã³ãã«ã«æããŸãã
䜿çšäŸ
ãã®ã¹ã¯ãªãããã¬ãŒã ã¯ãŒã¯ã®åäœã瀺ãããã«ããŠã£ã³ããŠã¢ããªã±ãŒã·ã§ã³ãããžã§ã¯ããäœæããŸããã ãŠã£ã³ããŠã®ã¬ã€ã¢ãŠãã¯ç°¡åã§ãã
<Window x:Class="IREngineTestBed.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Button x:Name="StartButton" Content="Start" Grid.Row="1" Margin="5" Height="25" Click="StartButton_Click"/> <Button x:Name="StopButton" Content="Stop" Grid.Row="1" Grid.Column="1" Margin="5" Height="25" Click="StopButton_Click"/> <ListBox x:Name="OutputLogList" Grid.Column="0" Margin="5"/> <ListBox x:Name="ErrorLogList" Grid.Column="1" Margin="5"/> </Grid> </Window>
ãããã«
ãŠã£ã³ããŠã«ã¯ã2ã€ã®ListBox'aãš2ã€ã®ãã¿ã³ãå«ãŸããŠããŸãã æååãè¿œå ããããã©ãŒãã³ã¹ãäœããããTextBlockã䜿çšããŠãã°ã衚瀺ããŸããã§ããïŒTextBlock.Text + =â some stringâ-ãåç¥ã®ããã«ã倧ããªæªããããŸãïŒã ããããå®éã«ã¯ãªã¹ãããã¯ã¹ã¯æªãèãã§ãã ããã¹ããã³ããŒããªãã§ãã ããã äžè¬ã«ãListBox'yã¯ãã¢çšã§ãïŒæ¥ãã§ïŒã å°æ¥çã«ã¯ãRichTextBoxã眮ãæããããšã«ãªãã§ãããã 圌ãã¯æååã®ä»®æ³åãæã£ãŠããããã§ãããã¹ãã¯StringBuilderã«è¿œå ãããŠããããã§ãã
ãã®ããããStartButtonããã¿ã³ã䜿çšããŠãã³ã³ãœãŒã«åºåãããã¡ãšã¹ã¯ãªããå®è¡ã¿ã¹ã¯ãç£èŠããããã®ã¿ã¹ã¯ã®ïŒåïŒéå§ãå®è¡ãããŸãã ãStopButtonããã¿ã³-ãã¹ãŠãåæ¢ããŸãã
ãã¹ãã¹ã¯ãªããã®ã³ãŒãã¯æ¬¡ã®ãšããã§ãã
#!ruby19 # encoding: utf-8 include IREngine class IRE def log(message) IRE.Instance.write_message message end def err(message) IRE.Instance.write_error message end end def log(message, is_err = false) IRE.Instance.log message unless is_err IRE.Instance.err message if is_err end 5.times{|i| log "Hello, Output! (from Ruby Async Task)" log "Hello, Error! (from Ruby Async Task)", true } raise "\n!!!\tBOOO! Catch super scaring exception from RUBY...\t!!!\n"
ãã®ã³ãŒãã§ã¯ãã¡ãã»ãŒãžããã°ã«åºåãããã«ããŒã¡ãœããããµãŒãã¹ã¯ã©ã¹ã«è¿œå ãããŸãã ããã«ãã·ã³ã°ã«ãã³ã€ã³ã¹ã¿ã³ã¹ã«è¿œå ã®ã¡ãœãããè¿œå ãããŸãã ããããã¡ãœããã®ååã«æ¥é èŸãselfããŸãã¯ãIREããä»ããå Žåããããã¯éçã¡ãœãããšããŠäœæãããŸãã ããããåŸã§è¡ããŸãïŒãã®ã±ãŒã¹ãåå¥ã«ãã¹ãããå¿ èŠããããŸãïŒã
ã¹ã¯ãªããã®æ¬æã«ã¯ããã°ãžã®è¡ã®5åã®åºåãšäŸå€è»¢éã衚瀺ãããŸãã ãã®äŸå€ã¯ããµãŒãã¹åŽã§æ£ããåŠçãããŸãã ããã¯ãã¹ã¯ãªããã®å®è¡åŸã®ã€ã³ã¿ãŒãã§ã€ã¹ã®å€èŠ³ã§ãã
![](https://habrastorage.org/storage2/3d8/4c7/773/3d84c7773c3457b203ca8390393f9161.png)
ãããã«
ãã®èšäºã§ã¯ãè€æ°ã®ã¹ã¯ãªãããåæã«éåæã§å®è¡ã§ãããšã³ãžã³ã®åºæ¬çãªå®è£ ã玹ä»ããŸããã å·çæç¹ã§ã¯ããã¹ãŠã®èšç»ãå®è£ ãããŠããããã§ã¯ãããŸããã ããšãã°ãã¹ã¯ãªããã®æ§æãšã©ãŒã®ç¶æ³ã®åŠçã®æ£ç¢ºæ§ã確èªããå¿ èŠããããŸãã ãŸããç¹å®ã®ã¹ã±ãžã¥ãŒã©ãŒã瀺ãã¹ã¯ãªããèµ·åã¡ãœããã¯ãŸã å®è£ ãããŠããŸããã
githubã®ãªããžããªã§ã³ãŒãã®éçºããã©ããŒã§ããŸãã 誰ãããããžã§ã¯ãã®éçºã«åå ããŠããããå¬ããã§ãã
ãæž èŽããããšãããããŸããïŒ