none
Многопоточная работа RRS feed

  • Вопрос

  • Приветствую.

    В продолжении прошлой темы про приостановку потоков возник такой вопрос. Есть такой метод:

    private int num = 1000000;
    
    private void DoSomething()
    {
       while (num != 0)
       {
          ...
       }
    }

    Производить какие-то действия с миллионом циклов последовательно - как-то не интересно. Думаю разбить действия на несколько потоков и делать все одновременно. Посоветуйте, пожалуйста, как тут быть с многопоточностью и, собственно, как сообщить каждому потоку с какого num необходимо стартовать?

    Заранее спасибо за ответы.

    15 июля 2013 г. 7:23

Ответы

  • Всё дело в том, что данный код не лучший пример для выполнения параллельно. В данном случае накладные расходы с использованием дополнительных потоков могут замедлить процесс. Поскольку однопоточная реализация очень простая и выполняется намного быстрей (используется только присваивание). Но стоит добавить больше вычислений, всё встанет на свои места.

    class Program
    {
      static void Main(string[] args)
      {
    
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    
    
        int[] array1 = new int[500000000];
    
        int[] array2 = new int[500000000];
    
        sw.Start();
    
        for(int i = 0; i < array1.Length; i++)
        {
          int j = 1;
          j = j + i;
          j--;
          array1[i] = j;
        }
    
        sw.Stop();
    
        Console.WriteLine(sw.ElapsedMilliseconds);
    
        sw.Reset();
        sw.Start();
    
        Parallel.For(0, array2.Length, (i) => {int j = 1;
          j = j + i;
          j--;
          array2[i] = j;
        });
    
        sw.Stop();
    
        Console.WriteLine(sw.ElapsedMilliseconds);
      }
    }


    Сделаем содержимое сообщества лучше, вместе!

    15 июля 2013 г. 9:34
    Модератор
  • Постарался максимально прозрачно ответить на Ваш вопрос.

    Сразу оговорюсь, вариантам решения вашего вопроса нет числа.

    Вариант 1 "Банальные потоки с параметром"

    void Start()
    {
        Thread Th1 = new Thread(DoSomethingStarter);
        Thread Th2 = new Thread(DoSomethingStarter);
    
        Th1.Start(new int[] { 1000000, 500000 });
        Th2.Start(new int[] { 500000, 0 });
    }
    
    void DoSomethingStarter(object Param)
    {
        int[] FromTo = (int[])Param;
        DoSomething(FromTo[0], FromTo[1]);
    }
    
    void DoSomething(int From, int To)
    {
        for (int i = From; i >= To; i--)
        {
            //your actions
        }
    }

    Вариант 2 "Потоки из пула потоков"

    void Start()
    {
        ThreadPool.QueueUserWorkItem(DoSomethingStarter, new int[] { 1000000, 500000 });
        ThreadPool.QueueUserWorkItem(DoSomethingStarter, new int[] { 500000, 0 });
    }
    
    void DoSomethingStarter(object Param)
    {
        int[] FromTo = (int[])Param;
        DoSomething(FromTo[0], FromTo[1]);
    }
    
    void DoSomething(int From, int To)
    {
        for (int i = From; i >= To; i--)
        {
            //your actions
        }
    }

    Если нужны еще варианты, обращайтесь.

    17 июля 2013 г. 3:31

Все ответы

  • Используйте ParallelFor из TPL.

    Сделаем содержимое сообщества лучше, вместе!

    15 июля 2013 г. 7:31
    Модератор
  • Правильно ли я понимаю, что это будет выглядеть как-то так?

    for (int i = 0; i < 10; ++i)
    {
       Thread thread = new Thread(DoSomething);
       thread.Start();
    }

    Только с передачей значения num в DoSomething, чтобы знать с какого значения начинать обратный отсчет.

    15 июля 2013 г. 7:34
  • Вот простенький пример:

    class Program
    {
      static void Main(string[] args)
      {
    
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    
    
        int[] array1 = new int[50000000];
    
        int[] array2 = new int[50000000];
    
        sw.Start();
    
        for(int i = 0; i < array1.Length; i++)
          array1[i] = i;
    
        sw.Stop();
    
        Console.WriteLine(sw.ElapsedMilliseconds);
    
        sw.Reset();
        sw.Start();
    
        Parallel.For(0, array2.Length, (i) => array2[i] = i);
    
        sw.Stop();
    
        Console.WriteLine(sw.ElapsedMilliseconds);
      }
    }


    Сделаем содержимое сообщества лучше, вместе!

    15 июля 2013 г. 7:55
    Модератор
  • Спасибо. Вечером буду разбираться, если что-то не будет получаться, то позвольте задавать вопросы. Еще раз спасибо.
    15 июля 2013 г. 8:10
  • Хм. Что-то не могу понять в чем фишка. В большинстве случаев первое число в два раза меньше второго. Иногда бывает, что второе меньше. По идее, тут должно быть наоборот, или я что-то путаю? Отчего такая ситуация?

    Спасибо.

    15 июля 2013 г. 9:20
  • Всё дело в том, что данный код не лучший пример для выполнения параллельно. В данном случае накладные расходы с использованием дополнительных потоков могут замедлить процесс. Поскольку однопоточная реализация очень простая и выполняется намного быстрей (используется только присваивание). Но стоит добавить больше вычислений, всё встанет на свои места.

    class Program
    {
      static void Main(string[] args)
      {
    
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    
    
        int[] array1 = new int[500000000];
    
        int[] array2 = new int[500000000];
    
        sw.Start();
    
        for(int i = 0; i < array1.Length; i++)
        {
          int j = 1;
          j = j + i;
          j--;
          array1[i] = j;
        }
    
        sw.Stop();
    
        Console.WriteLine(sw.ElapsedMilliseconds);
    
        sw.Reset();
        sw.Start();
    
        Parallel.For(0, array2.Length, (i) => {int j = 1;
          j = j + i;
          j--;
          array2[i] = j;
        });
    
        sw.Stop();
    
        Console.WriteLine(sw.ElapsedMilliseconds);
      }
    }


    Сделаем содержимое сообщества лучше, вместе!

    15 июля 2013 г. 9:34
    Модератор
  • Я вот заметил, что время Parallel.For больше только тогда, когда запускается приложение из-под студии. Если зайти хотя бы в папку Debug и запустить уже оттуда, то время на Parallel.For будет ниже.
    15 июля 2013 г. 10:03
  • Да, присоединённый отладчик имеет свои побочные действия, но это не всегда так.

    Сделаем содержимое сообщества лучше, вместе!

    15 июля 2013 г. 10:59
    Модератор
  • Постарался максимально прозрачно ответить на Ваш вопрос.

    Сразу оговорюсь, вариантам решения вашего вопроса нет числа.

    Вариант 1 "Банальные потоки с параметром"

    void Start()
    {
        Thread Th1 = new Thread(DoSomethingStarter);
        Thread Th2 = new Thread(DoSomethingStarter);
    
        Th1.Start(new int[] { 1000000, 500000 });
        Th2.Start(new int[] { 500000, 0 });
    }
    
    void DoSomethingStarter(object Param)
    {
        int[] FromTo = (int[])Param;
        DoSomething(FromTo[0], FromTo[1]);
    }
    
    void DoSomething(int From, int To)
    {
        for (int i = From; i >= To; i--)
        {
            //your actions
        }
    }

    Вариант 2 "Потоки из пула потоков"

    void Start()
    {
        ThreadPool.QueueUserWorkItem(DoSomethingStarter, new int[] { 1000000, 500000 });
        ThreadPool.QueueUserWorkItem(DoSomethingStarter, new int[] { 500000, 0 });
    }
    
    void DoSomethingStarter(object Param)
    {
        int[] FromTo = (int[])Param;
        DoSomething(FromTo[0], FromTo[1]);
    }
    
    void DoSomething(int From, int To)
    {
        for (int i = From; i >= To; i--)
        {
            //your actions
        }
    }

    Если нужны еще варианты, обращайтесь.

    17 июля 2013 г. 3:31