Вызов метода внутри нескольких задач C# - PullRequest
0 голосов
/ 30 апреля 2020

У меня проблема с вызовом метода в списке задач. У меня есть метод, который создает N количество задач. В каждой задаче я выполняю некоторые операции, которые в итоге приводят к выборке данных через HttpWebRequest и записи этих данных в файл. Я использую объекты блокировки, чтобы заблокировать доступ к общим ресурсам, таким как переменные. Все отлично работает, кроме вызова метода, который создает метод execute HttpWebRequest (метод GetData). Всякий раз, когда я не блокирую этот вызов метода (GetData), кажется, что некоторые данные / файлы пропускаются. Например:

  • С объектом блокировки я получаю файл 1,2,3 и 4
  • Без объекта блокировки я получаю файл 2,4 и 3

Вот код для метода, который создает задачи

private object lockObjectWebRequest= new object();
private object lockObjectTransactions = new object();

public List<Task> ExtractLoanTransactionsData(string URLReceived, string Headers, string Body)
{
    List<Task> Tasks = new List<Task>();

    try
    {
        int Limit = 0;
        int OffsetItemsTotal = 0;
        int NumberOftasks = 4;

        // Create the task to run in parallel
        for (int i = 0; i <= NumberOftasks; i++)
        {
            int OffsetCalculated = 0;

            if (i > 0)
            {
                OffsetCalculated = Limit * i;
            }

            Tasks.Add(Task.Factory.StartNew(() =>
            {
                string URL = URLReceived+ "&offset=" + OffsetCalculated .ToString() + "&limit=" + Limit.ToString();
                string Output = string.Empty;

                lock (lockObjectWebRequest)
                {
                    Output = GetData(URL, Headers,Body);
                }

                if (Output != "[]")
                {
                    lock (lockObjectTransactions)
                    {

                        Identifier++;
                        Job.Identifier = Identifier;

                        // write to file
                        string json = JValue.Parse(Output).ToString(Formatting.Indented);

                        string FileName = OffSet.ToString() + Identifier;
                        string Path = @"C:\FileFolder\" + FileName + ".json";

                        File.WriteAllText(Path, json);
                    }
                }

            }));
        }
    }
    catch (Exception ex)
    {
        Tasks = new List<Task>();
    }

    return Tasks;
}

Вот код, который выполняет HttpWebRequest:

public string GetData(string URL, string Headers, string Body)
{
    string Data = string.Empty;
    Headers = Headers.Trim('{').Trim('}');
    string[] HeadersSplit = Headers.Split(new char[] { ',', ':' });

    HttpWebRequest WebRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
    WebRequest.Credentials = new NetworkCredential();
    WebRequest.Method = "POST";

    HttpWebResponse WebResponse;

    // Set necessary Request Headers
    for (int i = 0; i < HeadersSplit.Length; i = i + 2)
    {
        string HeaderPart1 = HeadersSplit[i].Replace("\"", "").Trim();
        string HeaderPart2 = HeadersSplit[i + 1].Replace("\"", "").Trim();

        if (HeaderPart1 == "Content-Type")
        {
            WebRequest.ContentType = HeaderPart2;
        }
        else if (HeaderPart1 == "Accept")
        {
            WebRequest.Accept = HeaderPart2;
        }
        else if (HeaderPart1 == "Authorization")
        {
            WebRequest.Headers["Authorization"] = HeaderPart2;
        }
    }

    WebRequest.Headers.Add("cache-control", "no-cache");

    // Add body to Request
    using (var streamWriter = new StreamWriter(WebRequest.GetRequestStream()))
    {
        streamWriter.Write(Body);
        streamWriter.Flush();
        streamWriter.Close();
    }

     // Execute Request
     WebResponse = (HttpWebResponse)WebRequest.GetResponse();

     // Validate Response
     if (WebResponse.StatusCode == HttpStatusCode.OK)
     {
         using (var streamReader = new StreamReader(WebResponse.GetResponseStream()))
         {
             Data = streamReader.ReadToEnd();
         }
      }

     return Data;
}

Что я здесь не так делаю? Этот метод не имеет глобальных данных, которые совместно используются задачами.

1 Ответ

1 голос
/ 30 апреля 2020

Но у вас есть данные, которые совместно используются задачами: локальная переменная Identifier и аргумент метода Job.

Вы записываете в файл, используя Identifier в file- имя. Если блокировка не установлена, то этот фрагмент кода будет работать одновременно.

Последствия для Job не могут быть выведены из вашего вопроса.

Я думаю, что вы можете решить проблема с идентификатором:

var identifier = Interlocked.Increment(ref Identifier);
Job.Identifier = identifier; // Use 'identifier', not 'Identifier'

// write to file
string json = ...;

string FileName = OffSet.ToString() + "_" +
                  "MAMBU_LT_" + DateTime.Now.ToString("yyyyMMddHHmmss") + "_" +
                  identifier; // Use 'identifier', not 'Identifier'
...
...