c#任务无法在没有睡眠的情况下工作

and*_*rea 3 c# multithreading task

我在c#中使用Task在多线程中通过FTP发送文件.

这是我的函数(文件是一个字符串列表)

 Task<bool>[] result = new Task<bool>[file.Count];
        int j = 0;
        foreach (string f in file)
        {  
            result[j] = new Task<bool>(() => ftp.UploadFtp(f, "C:\\Prova\\" + f + ".txt", j));
            result[j].Start();
            j++;

            //System.Threading.Thread.Sleep(50);

        }
        Task.WaitAll(result, 10000);
Run Code Online (Sandbox Code Playgroud)

以及上传文件的功能

public static bool UploadFtp(string uploadFileName, string localFileName, int i)
    {
        FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://127.0.0.1/" + uploadFileName + ".txt");
        //settare il percorso per il file da uplodare
        //FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://desk.txt.it/");
        request.Method = WebRequestMethods.Ftp.UploadFile;

        request.Credentials = new NetworkCredential("ftp_admin", "");
        //request.Credentials = new NetworkCredential("avio", "avio_txt");
        try
        {
            Console.WriteLine(uploadFileName);
            Console.WriteLine(i);
            StreamReader sourceStream = new StreamReader(localFileName);
            byte[] fileContents = File.ReadAllBytes(localFileName);

            sourceStream.Close();
            request.ContentLength = fileContents.Length;

            Stream requestStream = request.GetRequestStream();
            requestStream.Write(fileContents, 0, fileContents.Length);
            requestStream.Close();

            FtpWebResponse response = (FtpWebResponse)request.GetResponse();

            //MessageBox.Show("Upload File Complete, status {0}", response.StatusDescription);

            response.Close();
            return true;
        }
        catch (Exception e)
        {
            return false;
        }

    }
Run Code Online (Sandbox Code Playgroud)

以这种方式,程序总是尝试保存列表的最后一个文件,但如果我添加一个Sleep(50),它会正确上传文件.似乎程序启动4个任务做同样的工作(保存最后一个文件)只有我不使用睡眠,但我不明白为什么,我不知道如何解决问题.

有人能帮我吗?谢谢

Jon*_*eet 9

看看你的代码:

int j = 0;
foreach (string f in file)
{  
    result[j] = new Task<bool>(() => ftp.UploadFtp(f, "C:\\Prova\\" + f + ".txt", j));
    result[j].Start();
    j++;
}
Run Code Online (Sandbox Code Playgroud)

lambda表达式使用每当执行时的当前值j.所以,如果在任务开始j递增,你会想念你的预期值.

在C#4中,你遇到了同样的问题f- 但这已在C#5中得到修复.有关详细信息,请参阅Eric Lippert的博客文章"关闭循环变量被认为有害".

最小的修复是微不足道的:

int j = 0;
foreach (string f in file)
{  
    int copyJ = j;
    string copyF = f;
    result[j] = new Task<bool>(
         () => ftp.UploadFtp(copyF, "C:\\Prova\\" + copyF + ".txt", copyJ));
    result[j].Start();
    j++;
}
Run Code Online (Sandbox Code Playgroud)

现在什么都不会改变copyJcopyF-你会得到一个单独的变量作为一个在每次循环抓获.在C#5中,您不需要copyF,而只需使用f.

...但我也建议使用Task.Factory.StartNew()(或Task.Run在.NET 4.5中)或仅使用Parallel.For.