Tor*_*lin 22 c# task-parallel-library
是否可以强制任务在当前线程上同步执行?
也就是说,通过例如传递一些参数StartNew()来制作这段代码是否可能:
Task.Factory.StartNew(() => ThisShouldBeExecutedSynchronously());
Run Code Online (Sandbox Code Playgroud)
表现得像这样:
ThisShouldBeExecutedSynchronously();
Run Code Online (Sandbox Code Playgroud)
背景:
我有一个名为的界面IThreads:
public interface IThreads
{
Task<TRet> StartNew<TRet>(Func<TRet> func);
}
Run Code Online (Sandbox Code Playgroud)
我想有两个这样的实现,一个使用线程的普通:
public class Threads : IThreads
{
public Task<TRet> StartNew<TRet>(Func<TRet> func)
{
return Task.Factory.StartNew(func);
}
}
Run Code Online (Sandbox Code Playgroud)
并且不使用线程(在某些测试场景中使用):
public class NoThreading : IThreads
{
public Task<TRet> StartNew<TRet>(Func<TRet> func)
{
// What do I write here?
}
}
Run Code Online (Sandbox Code Playgroud)
我可以让NoThreading版本调用func(),但我想返回一个Task<TRet>我可以执行操作的实例,例如ContinueWith().
dca*_*tro 11
你可以简单地返回func()包装的结果Task.
public class NoThreading : IThreads
{
public Task<TRet> StartNew<TRet>(Func<TRet> func)
{
return Task.FromResult(func());
}
}
Run Code Online (Sandbox Code Playgroud)
现在您可以将"继续"任务附加到此.
任务计划程序决定是在新线程上还是在当前线程上运行任务.有一个选项强制在新线程上运行它,但没有强制它在当前线程上运行.
但是有一个方法Task.RunSynchronously(),其
在当前TaskScheduler上同步运行任务.
更多关于MSDN.
此外,如果你正在使用async/await那里已经有一个类似的问题.
由于您提到测试,您可能更喜欢使用a,TaskCompletionSource<T>因为它还允许您设置例外或将任务设置为已取消(在.Net 4和4.5中工作):
返回已完成的任务,结果如下:
var tcs = new TaskCompletionSource<TRet>();
tcs.SetResult(func());
return tcs.Task;
Run Code Online (Sandbox Code Playgroud)
返回故障任务:
var tcs = new TaskCompletionSource<TRet>();
tcs.SetException(new InvalidOperationException());
return tcs.Task;
Run Code Online (Sandbox Code Playgroud)
返回已取消的任务:
var tcs = new TaskCompletionSource<TRet>();
tcs.SetCanceled();
return tcs.Task;
Run Code Online (Sandbox Code Playgroud)
在这里。这是我的最终解决方案(实际上解决的问题比我问的要多得多)。
Threads我在测试和生产中使用相同的实现,但传递不同的TaskSchedulers:
public class Threads
{
private readonly TaskScheduler _executeScheduler;
private readonly TaskScheduler _continueScheduler;
public Threads(TaskScheduler executeScheduler, TaskScheduler continueScheduler)
{
_executeScheduler = executeScheduler;
_continueScheduler = continueScheduler;
}
public TaskContinuation<TRet> StartNew<TRet>(Func<TRet> func)
{
var task = Task.Factory.StartNew(func, CancellationToken.None, TaskCreationOptions.None, _executeScheduler);
return new TaskContinuation<TRet>(task, _continueScheduler);
}
}
Run Code Online (Sandbox Code Playgroud)
我将其包装Task在一个TaskContinuation类中,以便能够指定TaskScheduler调用ContinueWith()。
public class TaskContinuation<TRet>
{
private readonly Task<TRet> _task;
private readonly TaskScheduler _scheduler;
public TaskContinuation(Task<TRet> task, TaskScheduler scheduler)
{
_task = task;
_scheduler = scheduler;
}
public void ContinueWith(Action<Task<TRet>> func)
{
_task.ContinueWith(func, _scheduler);
}
}
Run Code Online (Sandbox Code Playgroud)
我创建了TaskScheduler在创建调度程序的线程上分派操作的自定义:
public class CurrentThreadScheduler : TaskScheduler
{
private readonly Dispatcher _dispatcher;
public CurrentThreadScheduler()
{
_dispatcher = Dispatcher.CurrentDispatcher;
}
protected override void QueueTask(Task task)
{
_dispatcher.BeginInvoke(new Func<bool>(() => TryExecuteTask(task)));
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return true;
}
protected override IEnumerable<Task> GetScheduledTasks()
{
return Enumerable.Empty<Task>();
}
}
Run Code Online (Sandbox Code Playgroud)
TaskSchedulers现在我可以通过向构造函数传递不同的内容来指定行为Threads。
new Threads(TaskScheduler.Default, TaskScheduler.FromCurrentSynchronizationContext()); // Production
new Threads(TaskScheduler.Default, new CurrentThreadScheduler()); // Let the tests use background threads
new Threads(new CurrentThreadScheduler(), new CurrentThreadScheduler()); // No threads, all synchronous
Run Code Online (Sandbox Code Playgroud)
最后,由于事件循环在我的单元测试中不会自动运行,因此我必须手动执行它。每当我需要等待后台操作完成时,我都会执行以下操作(从主线程):
DispatcherHelper.DoEvents();
Run Code Online (Sandbox Code Playgroud)
可以在这里DispatcherHelper找到。
| 归档时间: |
|
| 查看次数: |
11994 次 |
| 最近记录: |