5

I have tried to upload +100 files to azure with Delphi. However, the calls block the main thread, so I want to do this with a async call or with a background thread.

This is what I do now (like explained here):

procedure TCloudManager.UploadTask(const input: TOmniValue;
  var output: TOmniValue);
var
  FileTask:TFileTask;
begin
  FileTask := input.AsRecord<TFileTask>;

  Upload(FileTask.BaseFolder, FileTask.LocalFile, FileTask.CloudFile);
end;

function TCloudManager.MassiveUpload(const BaseFolder: String;
  Files: TDictionary<String, String>): TStringList;
var
  pipeline: IOmniPipeline;
  FileInfo : TPair<String,String>;
  FileTask:TFileTask;
begin
  // set up pipeline
  pipeline := Parallel.Pipeline
    .Stage(UploadTask)
    .NumTasks(Environment.Process.Affinity.Count * 2)
    .Run;
  // insert URLs to be retrieved
  for FileInfo in Files do
  begin
    FileTask.LocalFile := FileInfo.Key;
    FileTask.CloudFile := FileInfo.Value;
    FileTask.BaseFolder := BaseFolder;

    pipeline.Input.Add(TOmniValue.FromRecord(FileTask));
  end;//for

  pipeline.Input.CompleteAdding;

  // wait for pipeline to complete
  pipeline.WaitFor(INFINITE);
end;

However this block too (why? I don't understand).

RRUZ
  • 134,889
  • 20
  • 356
  • 483
mamcx
  • 15,916
  • 26
  • 101
  • 189

2 Answers2

4

This blocks because you are calling WaitFor which waits for all pipeline stages to finish their work. During that wait, the GUI is blocked.

A proper way to do it is

  1. Store interface returned from Parallel.Pipeline in a global storage (for example in a TCloudManager field).
  2. Schedule work to the pipeline.
  3. Don't WaitFor end but assign OnStop handler and do whatever cleanup you need here (don't forget to nil out the global storage holding the pipeline interface).

To do step 3 you'll need fresh OmniThreadLibrary from the SVN because I just added this functionality :)

procedure TCloudManager.MassiveUpload(const BaseFolder: String;
  Files: TDictionary<String, String>);
var
  FileInfo : TPair<String,String>;
  FileTask:TFileTask;
begin
  // set up pipeline
  FPipeline := Parallel.Pipeline
    .Stage(UploadTask)
      .NumTasks(Environment.Process.Affinity.Count * 2)
    .OnStop(
      procedure begin
        ShowMessage('All done');
        FPipeline := nil;
      end)
    .Run;
//   insert URLs to be retrieved
  for FileInfo in Files do
  begin
    FileTask.LocalFile := FileInfo.Key;
    FileTask.CloudFile := FileInfo.Value;
    FileTask.BaseFolder := BaseFolder;

    FPipeline.Input.Add(TOmniValue.FromRecord(FileTask));
  end;//for
  FPipeline.Input.CompleteAdding;
end;
gabr
  • 26,580
  • 9
  • 75
  • 141
  • Not really. I would just do a Parallel.ForEach. – gabr Mar 26 '12 at 17:27
  • I try also with Parallel.ForEach, but I need to insert Application.ProcessMessages() and was not fluid. Perhaps because my lack of understanding of the use of the library... – mamcx Mar 26 '12 at 19:59
  • Now work well, but I lost the ability to update the main GUI. I use a Parallel.Async/OnTerminated... – mamcx Mar 26 '12 at 20:21
  • A more detailed example for such tasks: http://www.thedelphigeek.com/2011/10/omnithreadlibrary-in-practice-1web.html – Edwin Yip Oct 30 '12 at 04:54
-5

Delphi has a .NET variant, right? Were you aware there's a .NET Managed API for the Azure Storage Service?

The CloudBlockBlob class has an async variant for upload/download, etc.

http://msdn.microsoft.com/en-us/library/windowsazure/microsoft.windowsazure.storageclient.cloudblockblob_methods.aspx

sebastus
  • 350
  • 1
  • 7
  • Yes, that exist, but I need this in native delphi. – mamcx Mar 25 '12 at 22:39
  • 2
    -1. This has absolutely nothing to do with the question asked here, and shouldn't have been posted as an answer. – Ken White Mar 26 '12 at 01:16
  • Ken - how do you figure? If he's using Delphi.NET I gave him a library that is right on target - the ability to upload lots of files asynchronously. – sebastus Mar 26 '12 at 14:28
  • Because the .net variant of delphi is called delphi prism (http://www.embarcadero.com/products/prism) and the code that I post is nothing like .net. Is pure native delphi (probably something a non-delphi developer will not know) – mamcx Mar 26 '12 at 14:39
  • @Greg, he's NOT using Delphi.NET (which doesn't exist any longer, BTW), and the question was specifically about using OmniThreadLibrary. If the question had even had a tag related to .NET, maybe your answer could have been remotely related, but it doesn't. (OmniThreadLibrary, BTW, is a free, open source multithreading library written in Delphi, and is not .NET related either.) – Ken White Mar 26 '12 at 15:59