AK_*_*AK_ 0 .net c# multithreading asynchronous
我有一个实现某些服务的大型应用程序,它使用的接口是
IResult Execute(IRequest)
Run Code Online (Sandbox Code Playgroud)
它全部包含在IHttpHandler中.其中一些服务使用我想要替换的通用基础架构组件.问题是,我的组件需要很长时间才能运行,并且由于所有这些都托管在IIS服务器中,因此它将很快耗尽其工作线程.
我可以将服务包装在IHttpAsyncHandler中,但我仍然需要一种方法来异步使用我的组件,否则我将只是持有不同的工作线程.
我当然可以在它自己的线程中执行我的服务,但它非常昂贵.使用System.Threading.Tasks.Task或Delegate.BeginInvoke,只会占用另一个线程或工作线程,具体取决于实现.
理想情况下,我想如果可以的话,当我调用长时间运行的操作时,取出线程的堆栈和执行上下文,将它们放在一边,开始做我的工作(主要是IO和异步),释放线程即时使用到线程池\操作系统,完成后,将我保存的上下文放在一边,继续执行我的结果.
这在一些函数式语言中是非常可能的,或者在使用continuation时,如何在C#中实现?
在做了一些研究后,我认为我需要做的是一种延续.我需要冻结当前的执行线程堆栈,将线程释放回池中,并在我将使用的异步操作的回调上重新启动冻结的堆栈.
Justin Pihony的请求我正在添加一些代码来更好地描述我的问题.
这是我的Http Handler(当然简化):
class Handler: IHttpAsyncHandler
{
private readonly Action<HttpContext> _processDelegate = ProcessRequest;
public void ProcessRequest(HttpContext context)
{
IBuissnessService blThing = IOC.Get(context.Something);
// usually doesnt take too long...
thing.DoWork(context);
}
public bool IsReusable
{
get
{
return true;
}
}
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
return _processDelegate.BeginInvoke(context, cb, extraData);
}
public void EndProcessRequest(IAsyncResult result)
{
_processDelegate.EndInvoke(result);
}
}
//this is the buissness object
class BLThing :IBuissnessService
{
public void DoWork(HttpContext)
{
//.... a Lot of Stuff
// in some point one of the objects this is using does:
IDoWork someObject = IOC.GetSomthing();
var result = someObject.DoWork();
// uses the result some more
// and eventually returns.
}
}
class SomeObject : IDoWork
{
public Result DoWork()
{
// does some very long http call to another server
}
}
Run Code Online (Sandbox Code Playgroud)
我无法改变"BLThing"但我完全控制"SomeObject"也最终我需要支持"BLThing"期望的相同界面.
我想添加"SomeObject"两个异步方法(BeginDoWork,EndDoWork)并写入:
class SomeObjectWrapper : IDoWork
{
SomeObject _worker ;
public Result DoWork()
{
worker = new SomeObject();
ThreadState state = CurrentThread.CaptureState();
worker.BeginDoWork(Callback,state)
CurrentThread.PurgeStateAndReturnToPool();
}
void Callback(IAsyncResult result)
{
var processingResult = worker.EndDoWork(result);
ThreadState state =(ThreadState) result.AsyncState;
state.ReturnTopCall(processingResult);
CurrentThread.RestoreThreadState(state);
}
}
Run Code Online (Sandbox Code Playgroud)
好吧.Net这样做是不可能的.实际上它是,但需要大量的工作,并且可能不会产生任何性能优势,而不是创建一个完整的线程.这样的方法仅在本质上更具功能性的语言(或平台)中有益,并且具有与Win-API正在使用的内存和线程模型相当不同的内存和线程模型.
虽然如果最初以异步方式编写代码,或者依赖于TPL,他很可能很容易实现这一点......
我正在向贾斯汀颁发赏金,如果不是因为讨论的答案.
你为什么不使用任务库?在这种情况下,您不需要对线程池进行微观管理.如果Task真的是异步并等待,那么该线程将被其他东西使用,直到异步方法获得它正在等待的值为止?
尝试使用Tasks及其ContinueWith功能
Task t = Task.Factory.StartNew(code);
Task taskForSynchronous = t.ContinueWith(
(previousTask)=>{synchronous code after t is done},
TaskScheduler.FromCurrentSynchronizationContext()
);
newTask.ContinueWith(
(previousTask)=>{more asynchronous code}
);
Run Code Online (Sandbox Code Playgroud)
如果你真的在观察用法,你会发现线程池非常有效地管理它.