之前开发过的程序中,对于WPF的后台调用都是同步完成的,所以当要获取多个数据源进行绑定时,同步调用会让代码看起来很难看,同时也会影响系统的效率,因此从这里开始,我们开始研究如何将wpf的后台线程进行分配,最终到前后台线程都可以进行自由分配。
首先是参考:http://blog.csdn.net/harly5555/article/details/17657717 的文献,里面提供的方法帮助很大,这里先借助里面提供的一个方法,把我们的需求先做出个雏形,之后再对我们的方法进行探讨和深究。
我们借助文献中提到的Parallel.For方法,思路很简单,我们有一个action[]的数组,将所有需要异步调用的方法打包传递进我们自定义的方法,我们这里叫CustomizeDispatcher(),然后将数组中的所有action放入Parallel.For中执行,因为Parallel.For的方法之前介绍其实是异步调用的,那其实看上去,我们的需求的最底层模型应该已经可以通过这个简单的方法进行实现了。
代码:
public void CustomizeDispatcher(params Action[] actions)
{
ParallelLoopResult result = Parallel.For(0, actions.Length, (int ac) =>
{
actions[ac].BeginInvoke(null, null);
});
}
看似完成了,但是我们可以有一些补充和完善,对于action.BeginInvoke(),不多赘述了,但是这会有一个问题,如果我们有一个主线程,以及通过这个方法分配一些后台线程,那这些后台线程在进行时,主线程是否应该等待这些线程完成所有任务再继续执行?这里暂时我们需要这样的需求,我们不知道这些后台线程做完的方法对于整个主线程有什么影响,如果有影响,那当后台线程还没做完,主线程就继续进行了,那可能会导致不必要的异常,那如何让主线程等待这些线程呢?看上去我们要用EndInvoke方法了,重新调用endInvoke方法看上去很繁琐,我们直接把EndInvoke当作回调函数传给BeginInvoke呢?看上去很美,实际上结果会怎么样我也不知道,还需要把整个方法继续完善才会知道效果,我们先把代码写成下面这样:
public void CustomizeDispatcher(params Action[] actions)
{
ParallelLoopResult result = Parallel.For(0, actions.Length, (int ac) =>
{
AsyncCallback callback = (AsyncCallback)(asResult =>
{
actions[ac].EndInvoke(asResult);
});
actions[ac].BeginInvoke(callback, null);
});
}
套用文献中的说法:lamda表达式真是厉害。
接下来我们来调用:
static void Main(string[] args)
{
Run runmethod = new Run();
runmethod.CustomizeDispatcher(
() =>
{
Console.WriteLine(1);
Thread.Sleep(10000);
},
() =>
{
Console.WriteLine(2);
Thread.Sleep(10000);
},
() =>
{
Console.WriteLine(3);
Thread.Sleep(10000);
},
() =>
{
Console.WriteLine(4);
Thread.Sleep(10000);
});
Console.Read();
}
}
这样的运行结果是异步的,因此看上去我们很好的跨出了第一步,为了验证之前的endInvoke是否有效果,我们加入:
static void Main(string[] args)
{
Run runmethod = new Run();
runmethod.CustomizeDispatcher(
() =>
{
Console.WriteLine(1);
Thread.Sleep(10000);
},
() =>
{
Console.WriteLine(2);
Thread.Sleep(10000);
},
() =>
{
Console.WriteLine(3);
Thread.Sleep(10000);
},
() =>
{
Console.WriteLine(4);
Thread.Sleep(10000);
});
Console.WriteLine("Thread Complete");
Console.Read();
}
}
看下结果:
Thread Comlete
2
1
3
4
效果拔群,完全没效果。
稍微调查了下,我们把endInvoke当callback传入beginInvoke好像不太行得通,至少我们没见到EndInvoke应该出现的进程阻塞现象:
只能换成:
public void CustomizeDispatcher(params Action[] actions)
{
ParallelLoopResult result = Parallel.For(0, actions.Length, (int ac) =>
{
//AsyncCallback callback = (AsyncCallback)(asResult =>
//{
// actions[ac].EndInvoke(asResult);
//});
var ayResult = actions[ac].BeginInvoke(null, null);
actions[ac].EndInvoke(ayResult);
});
}
这样以后结果是对了,确实输出的结果出现在了1234之后,但是这显然未必不是我们要的,毕竟不是很整齐,
但是我还是对这个callback念念不忘,毕竟我们需要让整个方法更完整,让callback也变得可以自定义,因此在下一节中会对这个方法进行补充以及优化。