我需要使用SqlBulkCopy将大型csv文件分块到几个不同的数据库插入中。我打算通过2个单独的任务执行此操作,1用于批量处理CSV文件,另一个用于插入数据库。举个例子就是我的意思:
public class UberTask
{
private readonly BlockingCollection<Tuple<string,int>> _store = new BlockingCollection<Tuple<string, int>>();
public void PerformTask()
{
var notifier = new UINotifier();
Task.Factory.StartNew(() =>
{
for (int i =0; i < 10; i++)
{
string description = string.Format("Scenario {0}", i);
notifier.PerformOnTheUIThread(() => Console.WriteLine(string.Format("Reading '{0}' from file", description)));
// represents reading the CSV file.
Thread.Sleep(500);
notifier.PerformOnTheUIThread(() => Console.WriteLine(string.Format("Enqueuing '{0}'", description)));
_store.Add(new Tuple<string, int>(description, i));
}
_store.CompleteAdding();
});
var consumer = Task.Factory.StartNew(() =>
{
foreach (var item in _store.GetConsumingEnumerable())
{
var poppedItem = item;
notifier.PerformOnTheUIThread(() => Console.WriteLine(string.Format("Sending '{0}' to the database", poppedItem.Item1)));
// represents sending stuff to the database.
Thread.Sleep(1000);
}
});
consumer.Wait();
Console.WriteLine("complete");
}
}
这是配对2套相关任务的好方法吗?上面的代码没有处理(它需要):
对此有任何帮助将不胜感激!
答案 0 :(得分:2)
您可以使用异常处理和取消令牌来执行此操作。当管道阶段检测到错误时,它会捕获它并设置令牌。这将取消其他阶段。 finally块确保完成对CompleteAdding()的调用。这很重要,因为接收管道阶段可能会在收集等待时被阻止,并且在取消阻止之前不会处理取消。
您还希望在集合中删除任何未处理的对象,或者在管道阶段完成(在最后)和/或整个管道关闭时清理数据库连接。
以下是执行此操作的管道阶段的示例:
static void LoadPipelinedImages(IEnumerable<string> fileNames,
string sourceDir,
BlockingCollection<ImageInfo> original,
CancellationTokenSource cts)
{
// ...
var token = cts.Token;
ImageInfo info = null;
try
{
foreach (var fileName in fileNames)
{
if (token.IsCancellationRequested)
break;
info = LoadImage(fileName, ...);
original.Add(info, token);
info = null;
}
}
catch (Exception e)
{
// in case of exception, signal shutdown to other pipeline tasks
cts.Cancel();
if (!(e is OperationCanceledException))
throw;
}
finally
{
original.CompleteAdding();
if (info != null) info.Dispose();
}
}
整个管道代码如下所示。它还支持通过设置取消令牌从外部(从UI)取消管道。
static void RunPipelined(IEnumerable<string> fileNames,
string sourceDir,
int queueLength,
Action<ImageInfo> displayFn,
CancellationTokenSource cts)
{
// Data pipes
var originalImages = new BlockingCollection<ImageInfo>(queueLength);
var thumbnailImages = new BlockingCollection<ImageInfo>(queueLength);
var filteredImages = new BlockingCollection<ImageInfo>(queueLength);
try
{
var f = new TaskFactory(TaskCreationOptions.LongRunning,
TaskContinuationOptions.None);
// ...
// Start pipelined tasks
var loadTask = f.StartNew(() =>
LoadPipelinedImages(fileNames, sourceDir,
originalImages, cts));
var scaleTask = f.StartNew(() =>
ScalePipelinedImages(originalImages,
thumbnailImages, cts));
var filterTask = f.StartNew(() =>
FilterPipelinedImages(thumbnailImages,
filteredImages, cts));
var displayTask = f.StartNew(() =>
DisplayPipelinedImages(filteredImages.GetConsumingEnumerable(),
... cts));
Task.WaitAll(loadTask, scaleTask, filterTask, displayTask);
}
finally
{
// in case of exception or cancellation, there might be bitmaps
// that need to be disposed.
DisposeImagesInQueue(originalImages);
DisposeImagesInQueue(thumbnailImages);
DisposeImagesInQueue(filteredImages);
}
}
有关完整示例,请参阅下载中的Pipeline示例:
http://parallelpatterns.codeplex.com/releases/view/50473
在这里讨论: