C# 在当前线程上执行任务

C# 在当前线程上执行任务,c#,task-parallel-library,C#,Task Parallel Library,是否可以强制任务在当前线程上同步执行 也就是说,是否可以通过将某些参数传递给StartNew(),使此代码: Task.Factory.StartNew(()=>这应该同步执行()); 表现如下: 这应该同步执行(); 背景: 我有一个名为的接口,它的内容如下: 公共接口 { 任务开始新建(Func Func); } 我希望有两种实现,一种是使用线程的普通实现: 公共类线程:IThreads { 公共任务开始新建(Func Func) { 返回任务.Factory.StartNew(fun

是否可以强制任务在当前线程上同步执行

也就是说,是否可以通过将某些参数传递给
StartNew()
,使此代码:

Task.Factory.StartNew(()=>这应该同步执行());
表现如下:

这应该同步执行();
背景:

我有一个名为
的接口,它的内容如下:

公共接口
{
任务开始新建(Func Func);
}
我希望有两种实现,一种是使用线程的普通实现:

公共类线程:IThreads
{
公共任务开始新建(Func Func)
{
返回任务.Factory.StartNew(func);
}
}
以及不使用线程的线程(在某些测试场景中使用):

public类NoThreading:IThreads
{
公共任务开始新建(Func Func)
{
//我在这里写什么?
}
}

我可以让
NoThreading
版本只调用
func()
,但我想返回
Task
的一个实例,我可以在该实例上执行操作,例如
ContinueWith()

任务调度器决定是在新线程上还是在当前线程上运行任务。有一个选项可以强制在新线程上运行它,但没有一个选项可以强制它在当前线程上运行

但是有一个方法
Task.RunSynchronously()
,它

在当前TaskScheduler上同步运行任务

更多关于


另外,如果您使用的是
async/await
,则该任务上已经有一个函数。

您只需返回封装在
任务中的
func()
的结果即可

public class NoThreading : IThreads
{
    public Task<TRet> StartNew<TRet>(Func<TRet> func)
    {
        return Task.FromResult(func());
    }
}
public类NoThreading:IThreads
{
公共任务开始新建(Func Func)
{
返回Task.FromResult(func());
}
}

现在,您可以将“继续”任务附加到此任务。

是的,您可以使用自定义任务调度器来完成这项工作

internal class MyScheduler : TaskScheduler
{
    protected override IEnumerable<Task> GetScheduledTasks()
    {
        return Enumerable.Empty<Task>();
    }

    protected override void QueueTask(Task task)
    {
        base.TryExecuteTask(task);
    }

    protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
    {
        base.TryExecuteTask(task);
        return true;
    }
}

static void Main(string[] args)
{
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " Main");

    Task.Factory.StartNew(() => ThisShouldBeExecutedSynchronously(), CancellationToken.None, TaskCreationOptions.None, new MyScheduler());
}
内部类MyScheduler:TaskScheduler
{
受保护的重写IEnumerable GetScheduledTasks()
{
返回可枚举的.Empty();
}
受保护的覆盖无效队列任务(任务任务)
{
base.TryExecuteTask(任务);
}
受保护的覆盖bool TryExecuteTaskInline(任务任务,bool任务先前排队)
{
base.TryExecuteTask(任务);
返回true;
}
}
静态void Main(字符串[]参数)
{
WriteLine(Thread.CurrentThread.ManagedThreadId+“Main”);
Task.Factory.StartNew(()=>这应该同步执行(),CancellationToken.None,TaskCreationOptions.None,new MyScheduler());
}

既然您提到了测试,您可能更喜欢使用,因为它还允许您设置异常或将任务设置为已取消(适用于.Net 4和4.5):

返回已完成的任务及其结果:

var tcs = new TaskCompletionSource<TRet>();
tcs.SetResult(func());
return tcs.Task;
var tcs=new TaskCompletionSource();
SetResult(func());
返回tcs.Task;
返回出现故障的任务:

var tcs = new TaskCompletionSource<TRet>();
tcs.SetException(new InvalidOperationException());
return tcs.Task;
var tcs=new TaskCompletionSource();
SetException(新的InvalidOperationException());
返回tcs.Task;
返回已取消的任务:

var tcs = new TaskCompletionSource<TRet>();
tcs.SetCanceled();
return tcs.Task;
var tcs=new TaskCompletionSource();
setCancelled();
返回tcs.Task;

点击这里。这是我的最终解决方案(实际上解决的问题比我问的要多得多)

在测试和生产中,我对
线程使用了相同的实现,但传入了不同的
任务调度器

公共类线程
{
专用只读任务调度器\u executeScheduler;
专用只读任务调度器_continueScheduler;
公共线程(TaskScheduler executeScheduler、TaskScheduler continueScheduler)
{
_executeScheduler=executeScheduler;
_continueScheduler=continueScheduler;
}
公共任务延续开始新建(Func Func)
{
var task=task.Factory.StartNew(func,CancellationToken.None,TaskCreationOptions.None,_executeScheduler);
返回新的TaskContinuation(任务,_ContinuateScheduler);
}
}
我将
任务
包装在
TaskContinuation
类中,以便能够为
continuateWith()调用指定
TaskScheduler

公共类任务继续
{
私有只读任务_任务;
专用只读任务调度程序_调度程序;
公共任务延续(任务任务、任务计划程序)
{
_任务=任务;
_调度程序=调度程序;
}
公共无效继续(行动职能)
{
_任务.ContinueWith(func,_调度程序);
}
}
我创建自定义的
TaskScheduler
,在创建调度程序的线程上调度操作:

公共类CurrentThreadScheduler:TaskScheduler
{
专用只读调度程序\u调度程序;
公共CurrentThreadScheduler()
{
_dispatcher=dispatcher.CurrentDispatcher;
}
受保护的覆盖无效队列任务(任务任务)
{
_dispatcher.BeginInvoke(新函数(()=>TryExecuteTask(任务));
}
受保护的覆盖bool TryExecuteTaskInline(任务任务,bool任务先前排队)
{
返回true;
}
受保护的重写IEnumerable GetScheduledTasks()
{
返回可枚举的.Empty();
}
}
现在,我可以通过将不同的
任务调度器
传递给
线程
构造函数来指定行为

新线程(TaskScheduler.Default,TaskScheduler.FromCurrentSynchronizationContext());//生产
新线程(TaskScheduler.Default,new CurrentThreadScheduler());//让测试使用后台线程
新线程(新CurrentThreadScheduler(),新CurrentThreadScheduler());//没有线程,所有线程都是同步的
最后,由于事件循环在我的单元测试中不会自动运行,所以我必须手动执行它。每当我需要等待后台操作完成时,我都会(从主线程)执行以下操作:

DispatcherHelper.DoEvents();