#c_sharp
Как правильно уменьшить размер стека для .NET приложения? Возможно есть какие либо директивы или опции в Visual Studio.
Ответы
Ответ 1
Вы можете, например, воспользоваться конструктором Thread с указанием максимального размера стека. Если вы планируете запускать Task на этом потоке, имеет смысл реализовать TaskScheduler, который перекинет Task в этот поток. Или можно воспользоваться готовым scheduler'ом, например, WPF. Пример кода: При помощи этого метода можно «перебросить» async-метод в поток, на котором бежит данный WPF-диспетчер: static class AsyncHelper { public static DispatcherRedirector RedirectTo(Dispatcher d) { return new DispatcherRedirector(d); } } // http://blogs.msdn.com/b/pfxteam/archive/2011/01/13/10115642.aspx public struct DispatcherRedirector : INotifyCompletion { public DispatcherRedirector(Dispatcher dispatcher) { this.dispatcher = dispatcher; } #region awaiter public DispatcherRedirector GetAwaiter() { // combined awaiter and awaitable return this; } #endregion #region awaitable public bool IsCompleted { get { // true means execute continuation inline return dispatcher.CheckAccess(); } } public void OnCompleted(Action continuation) { dispatcher.BeginInvoke(continuation); } public void GetResult() { } #endregion Dispatcher dispatcher; } Теперь вам нужен поток, в котором бежит диспетчер. public class DispatcherThread : IDisposable { public Dispatcher Dispatcher { get; private set; } public TaskScheduler TaskScheduler { get; private set; } Thread thread; public DispatcherThread(int maxStackSize) { using (var barrier = new AutoResetEvent(false)) { thread = new Thread(() => { Dispatcher = Dispatcher.CurrentDispatcher; barrier.Set(); Dispatcher.Run(); }, maxStackSize); thread.SetApartmentState(ApartmentState.STA); thread.Start(); barrier.WaitOne(); } TaskScheduler = Get(() => TaskScheduler.FromCurrentSynchronizationContext()); } // --------------------------------------------- // остальные функции вам не нужны для вашей задачи, но могут пригодиться впоследствии public void Execute(Action a) { if (Dispatcher.CheckAccess()) a(); else Dispatcher.Invoke(a); } public void FireAndForget(Action a) { Dispatcher.BeginInvoke(a); } public T Get(Func getter) { if (Dispatcher.CheckAccess()) return getter(); else { T t = default(T); Dispatcher.Invoke((Action)(() => { t = getter(); })); return t; } } public Task GetAsync (Func getter) { return Dispatcher.InvokeAsync(getter).Task; } public Task StartNewTask(Action action) { return Task.Factory.StartNew( action: action, cancellationToken: CancellationToken.None, creationOptions: TaskCreationOptions.None, scheduler: TaskScheduler); } public Task StartNewTask (Func function) { return Task.Factory.StartNew( function: function, cancellationToken: CancellationToken.None, creationOptions: TaskCreationOptions.None, scheduler: TaskScheduler); } public void Dispose() { Dispatcher.InvokeShutdown(); if (thread != Thread.CurrentThread) thread.Join(); } } Этим можно пользоваться, например, так: using (var t = new DispatcherThread(maxStackSize)) { await AsyncHelper.RedirectTo(t.Dispatcher); // остаток метода } Обновление: совсем забыл, надо же по идее сбежать из умирающего потока! Например, в thread pool. static class AsyncHelper { public static ThreadPoolRedirector RedirectToThreadPool() { return new ThreadPoolRedirector(); } } public struct ThreadPoolRedirector : INotifyCompletion { #region awaiter public ThreadPoolRedirector GetAwaiter() { // combined awaiter and awaitable return this; } #endregion #region awaitable public bool IsCompleted { get { // true means execute continuation inline return Thread.CurrentThread.IsThreadPoolThread; } } public void OnCompleted(Action continuation) { ThreadPool.QueueUserWorkItem(o => continuation()); } public void GetResult() { } #endregion } и использовать как using (var t = new DispatcherThread(maxStackSize)) { await AsyncHelper.RedirectTo(t.Dispatcher); // остаток метода await AsyncHelper.RedirectToThreadPool(); } Хотя может быть это и не нужно, InvokeShutdown не убивает поток немедленно. Но тем не менее. Более современная версия DispatcherThread — в этом ответе.
Комментариев нет:
Отправить комментарий