3

さて、これが状況です...私は毎秒約8ファイルを生成するアプリケーションを持っています。各ファイルは19〜24kbです。これにより、1分あたり約10〜11MBが生成されます。私はすでにその解決策を持っているので、この質問はftpの方法に関するものではありません...質問はデータの流れに追いつく方法に関するものです(クライアントサイトに移動している場合を除き、ほとんどの場合、アップロード帯域幅は2MBのみです)大きなパイプがあります)。ftpの転送に時間がかかり、フローの速度よりも長くかかるかどうかは気にしませんが、ftpプロセスが終了すると、転送したファイルだけが削除されるように、ファイルをバッチ処理して移動する方法について誰かが考えているかどうかを知りたいです。その後、次のバッチに進みます。これが私が考えていたものです:

アプリをマルチスレッド化し、最初のスレッドはアプリを実行し、2番目のスレッドは「N」分ごとにテキストファイルを作成し、その期間に作成されたすべてのファイルを含むタイマーです。ファイルをStreamReadし、テキスト内のファイルを別の場所に移動し(おそらく、一時フォルダーを作成します)、それらのファイルをftpで送信し、ファイル、フォルダー、およびテキストファイルを削除します...その間に、さらに多くのテキストファイルが書き込まれ、一時作成中のフォルダ。これは実行可能ですか?誰もがアドバイスを受けている提案をすべて取り上げ、最速で最も信頼できるパスを探します。

コードを見るように頼まないでください。私たちが仮説を扱っていることを考えると、コードを見る理由はありません。

4

7 に答える 7

4

サービスを作成し、FileSystemWatcher、System.Threading.Timer、またはその両方を使用して、受信ファイルを同時コレクションに追加します(FileSystemWatcherは、バッファーがオーバーランするとファイルを見逃す可能性があるため、タイマーでファイルを取得することをお勧めします見逃している)。ファイルが入ってくると、それらを別のフォルダーに移動し、.NET4.0タスクを使用して処理します。次に、元のタスクの継続ステップで必要な後処理を行います。障害を処理する継続ステップと、成功時に発生するさまざまな継続ステップを設定できます。これらの各タスクは、スレッドプール内のスレッドを起動し、自動的に管理されます。

これは、OnlyOnFaulted継続タスクのhttp://msdn.microsoft.com/en-us/library/dd997415.aspxの例です。成功した場合にのみ実行される2番目の継続タスクを持つことができます。

var task1 = Task.Factory.StartNew(() =>
{
    throw new MyCustomException("Task1 faulted.");
})
.ContinueWith((t) =>
    {
        Console.WriteLine("I have observed a {0}",
            t.Exception.InnerException.GetType().Name);
    },
    TaskContinuationOptions.OnlyOnFaulted);
于 2011-05-27T14:35:50.760 に答える
1

Wihtout realy knowing any more details on why you need to keep all the work in a single application and deal with threading complexity, one could argue to keep the part that generates the files and the part that FTPs the files in separate applications.

Separation of Responsibility. Ensure each application does only one job and does it right and fast.

One Serivce or app(desktop/web which ever) generating the files.

Another Service which watches a folder and moves any incoming files into a temp filder, does what it needs to do, FTPs and deletes.

Seeing I don't know your setup and where you get the content from for your files, writing it in a single app might be the best choice exactly how you suggested.

Basically to anwser your question. Yes, it does sound feasable what you want to do. How you implement it and what you are happy with implementing is up to you.

If you get stuck somewhere during implementation, feel free to post any issues in a new threat with some code samples on how you have a specific feature implemented and what the issue is you are experiencing.

Until then, hypothetically, any approach you feel is able to manage what you need to achieve is perfectly valid.

EDIT

Seeing you stated you already got the application which generates the files done and you already have a solution which FTPs means using 2 separate applications sounds more plausible.

All you need then is wrap a service around the FTP solution and happy days. No need to interfeere with the original application which generates the files if it is already working.

Why risk breaking it, unless you must add the fTP feature into it and you have no choice.

于 2011-05-27T14:36:58.890 に答える
1

私は以前の仕事で似たようなことに取り組みました。外部プロセスが特定のフォルダにファイルをダンプします。これは私が従ったアルゴリズムです:

  1. ファイルがダンプされるソースディレクトリでFileSystemWatcherを実行します
  2. 新しいファイルが見つかったら、ディレクトリからすべてのファイルを日付の昇順で処理します。(あなたの場合、ファイルをftpで転送します)
  3. ファイルが処理されたら、それらをProcessedディレクトリに移動します(この場合、ファイルを削除できます)

考慮事項:

  1. 開いているftp接続/処理スレッドの数はいくつありますか
  2. FileSystemWatcherは、別のファイルを処理するときにイベントを発生させることができます。それを処理する方法/適切なスレッドに送信する
于 2011-05-27T14:52:42.897 に答える
0

このような状況でFTPサーバーの所有者として、可能な限りサインオンを維持する方法を見つけてください。

サインオン/オフは、多くの場合、個々のファイル転送よりも「高価」です(計算、構成のブロックなどの点で)。

于 2011-06-21T03:29:20.077 に答える
0

プロデューサーが速すぎる場合にファイルをバッファリングできるようにするには、ファイルのプロデューサーとコンシューマー(FTPホスト)の間にキューを挿入する必要があります。これには、何らかの形式のマルチスレッドまたは複数のプロセスが必要です。

キューがファイルシステムであり、それは非常に可能ですが、多くの場合理想的ではないソリューションを提案します。半分満たされたファイルや空のファイルなどを転送しないように、正しくロックする必要があります。ファイルシステムを使用することにした場合、FileSystemWatcherその目的に使用できないのは私の経験です。タイマーを使用してタスクを実行し、毎秒新しいファイルを取得する方がはるかに信頼性が高くなります。

他のキューテクノロジには、メモリ内キュー(ただし、クラッシュの処理方法を検討する必要があります)、プライベートMicrosoftメッセージキュー、またはSQLServerブローカーキューがあります。最善の解決策は、要件によって大きく異なります。

FTPは実際にはトランザクションではないため、トランザクションではないキューを使用することもできます(MSMQとSQL Server Brokerはどちらもトランザクションです)が、ファイルが作成され、キューに入れられるトランザクションの概念に基づいてアプリケーションを構築する必要があります。配信されます。配信できない場合はキューに残され、後で配信が再試行されます。キューに入れることができない場合、プロデューサーはキューに入れるなどを再試行する必要があります。ファイルが配信されない、または2回配信されるような状況は望ましくありません。

FTPをどのように使用するかは質問からは明らかではありませんが、オープンソースまたは商用ライブラリを使用して、にシェルアウトするのではなく、アプリケーションからFTPを直接使用できるようにすることをお勧めしますftp.exe。これにより、アプリケーションはFTP接続を開いたままにしておくことについてインテリジェントに動作し、過度の再接続などを回避できます。

また、キューが大きくなりすぎた状況に対処する方法も検討する必要があります。1つのオプションは、キューサイズがしきい値を下回るまでプロデューサーを停止することです。

于 2011-05-27T14:57:21.850 に答える
0
  1. 1秒に1回起動するタイマーを開始します。
  2. タイマーの経過イベントハンドラーで、タイマーを停止します。
  3. 着信ディレクトリ内のすべてのファイルのリストを取得します。
  4. 各ファイルを排他的に開くようにしてください。これにより、まだ書き込まれているファイルを読み取ることができなくなります。
  5. 各ファイルをステージングディレクトリにコピーし、受信ディレクトリから削除します。
  6. リスト内のすべてのファイルを移動したら、FTP経由でステージングディレクトリ内のファイルを送信します。
  7. ファイルをFTPで転送したら、ステージングディレクトリからファイルを削除します。
  8. タイマーを開始します。

タイマーの経過ハンドラーはスレッドプールで実行されるため、より高度なスレッド管理が必要になります。主な制約はFTP帯域幅であるため、ファイルがアップロードされるまで、他のスレッドで他のことを行う利点はほとんどありません。

このアプローチにより、システムがクラッシュした場合の保護が提供されます。送信されないステージングディレクトリにあるファイルは、次のサイクルで取得されます。着信ディレクトリ内のファイルについても同じことが言えます。

FTP受信側がzipファイルを処理できる場合は、ステージングディレクトリの内容をzipして、1つのファイルとして送信することでスループットを向上させます。

于 2011-05-27T19:06:03.200 に答える
0

BlockingCollectionsを使用してスレッドのチェーンを設定します。

1つのプロデューサースレッドは、タイマーやFileSystemWatcherなどを使用して、使用可能なファイルを読み取り、BlockingCollectionに保存します。また、ファイルをリストに保存して、ファイルが1回だけ追加されるようにします。

var availableFiles = new BlockingCollection<string>();
var processedFiles = new BlockingCollection<string>();
var newFiles = new HashSet<string>();

...
lock (newFiles) {
    foreach (var file in Directory.GetFiles())
        if (!newFiles.Contains(file)) {
            availableFiles.Add(file);
            newFiles.Add(file);
        }
}

1つ以上のftpスレッドがファイルを送信し、処理されたコレクションに入れます

foreach (var file in availableFiles.GetConsumingEnumerable()) {
   SendFileOverFtp(file);
   processedFiles.Add(file);
}

処理されたファイルをクリーンアップする1つのスレッド

foreach (var file in processedFiles.GetConsumingEnumerable()) {
    lock (newFiles) {
       File.Delete(file);
       newFiles.Remove(file);
    }
}

もう1つの方法は、生成スレッドにファイルをメモリに読み込んで削除させることです。その場合、最後のステージとnewFilesコレクションをスキップできます

于 2011-05-28T19:18:51.860 に答える