我正在尝试在执行任务之前构建一个任务列表。这是一些示例代码:
public string Returnastring(string b)
{
return b;
}
public string Returnanotherstring(string a)
{
return a;
}
private void btnT_Click(object sender, EventArgs e)
{
bool cont = true;
var Returnastringtask = Task.Factory.StartNew(() => Returnastring("hi"));
var Returnanotherstringtask = Task.Factory.StartNew(() => Returnanotherstring("bye"));
if (cont)
{
Task.WaitAll(new Task[] { Returnastringtask });
}
else
{
Task.WaitAll(new Task[] { Returnanotherstringtask });
}
我知道这个代码并不像我预期的那样运行两个任务。我想基本上创建任务,然后根据bool执行一个或另一个。我不想在真假条件下创建任务,因为我想避免代码复制。通过这个我的意思是如果cont是真的我可能想要运行任务1,2,3,4但如果cont是假我可能想要运行任务2,3,7,8。
答案 0 :(得分:12)
嗯,另一种方法,(我发现非常直接)
var list = new List<Task>();
for (var i = 0; i < 10; ++i)
{
var i2 = i;
var t = new Task(() =>
{
Thread.Sleep(100);
Console.WriteLine(i2);
});
list.Add(t);
t.Start();
}
Task.WaitAll(list.ToArray());
答案 1 :(得分:7)
而不是使用Task.Factory.StartNew
来创建任务(线索在名称中),而只是使用new Task(...)
和lambda来创建它们,然后在条件中使用taskName.Start()
你想开始他们。
答案 2 :(得分:1)
您可以根据标志创建Action
数组,然后使用Parallel.Invoke()
并行运行数组中的所有操作并等待它们完成。
如果需要,可以将lambdas用于允许您将其返回值分配给局部变量的操作。
这是一个完整的可编辑示例。试着getFlag()
返回true
并再次返回false
:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
sealed class Program
{
void run()
{
bool flag = getFlag();
var results = new string[5];
Action[] actions;
if (flag)
{
actions = new Action[]
{
() => results[0] = function("f1"),
() => results[1] = function("f2"),
() => results[2] = function("f3")
};
}
else
{
actions = new Action[]
{
() => results[3] = function("f4"),
() => results[4] = function("f5")
};
}
Parallel.Invoke(actions); // No tasks are run until you call this.
for (int i = 0; i < results.Length; ++i)
Console.WriteLine("Result {0} = {1}", i, results[i]);
}
private bool getFlag()
{
return true; // Also try with this returning false.
}
string function(string param)
{
Thread.Sleep(100); // Simulate work.
return param;
}
static void Main(string[] args)
{
new Program().run();
}
}
}
答案 3 :(得分:0)
Task.Factory.StartNew实际上将开始你的任务。您想要设置任务,然后根据某些逻辑运行它们。
您可以在任何地方构建您的任务,但您应该在逻辑之后启动它们。这个例子在逻辑之后构建它们。
也许你可以像这样运行它:
If(A)
{
doA();
}
Else
{
doB();
}
然后在您调用的函数中启动任务:
public void doA()
{
for (int i = 0; i < NumberOfTasks; i++)
{
tasks[i] = Task.Factory.StartNew(() =>
{
try
{
//enter tasks here
// i.e. task 1, 2, 3, 4
}
}
}, token);
Task.WaitAll(tasks);
}
答案 4 :(得分:0)
我以Samuel的工作为基础,但我有一个递归事件处理程序需要完成它的工作,因为它的子事件取决于它的完成(用于将控件嵌套在ASP.NET应用程序的动态UI中) )。因此,如果您想做同样的事情,除了要处理一个事件,而且您不是多线程的,因为您需要同步处理多个任务,而又不会在调用堆栈中费力。
private static Queue<Task> _dqEvents = new Queue<Task>();
private static bool _handlingDqEvent = false;
protected void HandleDynamicQuestion(int SourceQuestionId, int QuestionId)
{
//create a task so that we can handle our events in sequential order, since additional events may fire before this task is completed, and depend upon the completion of prior events
Task task = new Task(() => DoDynamicQuestion(SourceQuestionId, QuestionId));
lock(_dqEvents) _dqEvents.Enqueue(task);
if (!_handlingDqEvent)
{
try
{
//lockout any other calls in the stack from hitting this chunk of code
lock (_dqEvents) _handlingDqEvent = true;
//now run all events in the queue, including any added deeper in the call stack that were added to this queue before we finished this iteration of the loop
while (_dqEvents.Any())
{
Task qt;
lock (_dqEvents) qt = _dqEvents.Dequeue();
qt.RunSynchronously();
}
}
finally
{
lock (_dqEvents) _handlingDqEvent = false;
}
}
else
//We exit the method if we're already handling an event, as the addition of new tasks to the static queue will be handled synchronously.
//Basically, this lets us escape the call stack without processing the event until we're ready, since the handling of the grandchild event
//is dependent upon its parent completing.
return;
}
private void DoDynamicQuestion(int SourceQuestionId, int QuestionId)
{
//does some stuff that has no dependency on synchronicity
//does some stuff that may eventually raise the event above
//does some other stuff that has to complete before events it triggers can process correctly
}