Action a = ()=>{ do some work}; a.BeginInvoke(CB, a); void CB(IAsyncResult ar) { Action a = ar.AsyncState as Action; a.EndInvoke(ar); } (1) It seems UI Async cannot be implemented in Fx 4.0. We have to wait for Fx 4.5 async-await to have non-blocking UI (2) AsyncRollingFile is "async-like", slightly block UI. In my test it blocking UI for 9 seconds, then writing file take 40 seconds to complete. It is definetly faster than classic Log4net RollingFile which block UI by the entire 40 secs. (3) Log4Net achieved Async by using Task offloading logging from a queue-like buffer.I also tried TaskCompletionSource and it has similar "short-blocking" async behavior. (4) All these async-alike can lose 20 seconds of data during delayed write to files since app can crash. That is when we really need to log why the app crashed. (5) Fx 4.0 already has a solution to deal with Buffer overflow in Log4NetAsync --- instead of throw away logging, we can block logging. So we slow down but do no lose data. Specifically, I think we can implement IProducerConsumer using RingBuffer (so 2x faster writing files) and feed it to BlockingCollection with Capacity 1000. I tried BlockingCollection, capacity 10 or 1000, default ConcurrentQueue, end up Blocking UI for 20 secs and 70 sec write to files. so much slower. Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 0; i < Int32.MaxValue / 1000; i++) // your Log.Info sw.Stop(); MessageBox.Show(sw.ElapsedMilliseconds.ToString()); namespace Log4Net.Async { public class AsyncRollingFileAppender : RollingFileAppender { BlockingCollection<LoggingEvent> pendingAppends = new BlockingCollection<LoggingEvent>(10); Task t ; public override void ActivateOptions() { base.ActivateOptions(); t = new Task(AppendLoggingEvents,TaskCreationOptions.PreferFairness); t.Start(); } protected override void Append(LoggingEvent[] loggingEvents) { Array.ForEach(loggingEvents, Append); } protected override void Append(LoggingEvent loggingEvent) { Task.Factory.StartNew(() => { if (FilterEvent(loggingEvent)) { pendingAppends.Add(loggingEvent); } }); } private void AppendLoggingEvents() { LoggingEvent loggingEventToAppend; while (true) { while (!pendingAppends.TryTake(out loggingEventToAppend)) { } if (loggingEventToAppend == null) { continue; } try { base.Append(loggingEventToAppend); } catch { } } while (pendingAppends.TryTake(out loggingEventToAppend)) { try { base.Append(loggingEventToAppend); } catch { } } } } }
Blog Archive
Sunday, September 14, 2014
Classical Asyn Pattern and "AsyncRollingFileAppender" using BlockingCollection in Log4Net
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment