Деление повторений цикла среди потоков

Во-первых: вы не можете изменить расширение .png на .gif, чтобы получить файл GIF. Вам придется использовать какую-то программу для его преобразования. Но Image.open может работать с файлами PNG, поэтому вам не нужно конвертировать его.

 img = ImageTk.PhotoImage(Image.open("furas.png"))

Второе: есть ошибка в PhotoImage, которая удаляет изображение из памяти, когда оно назначается локальной переменной в функции. Поэтому вы должны назначить его глобальной переменной. Обычный метод назначает его метке, которая будет отображать его. Вы можете использовать любое имя для переменной - т.е. .image

 la.image = img

Подробнее в документации: PhotoImage на effbot.org

Третье: вы запустили код в терминале, чтобы увидеть ошибку Сообщения ? Вы забыли импортировать subprocess

Полный код с существующим изображением

from tkinter import *
from PIL import ImageTk, Image
import subprocess

def callback(event):
    subprocess.call("wget https://blog.furas.pl/theme/images/me/furas.png", shell=True)
    img = ImageTk.PhotoImage(Image.open("furas.png"))
    la.configure(image=img)
    la.image = img

root = Tk()
root.title("My app")
root.geometry("680x500+0+0")

b1 = Button(root, text="b1", bg="red")
b1.grid(row=0, column=0)

b2 = Button(root, text="b2", bg="blue")
b2.grid(row=0, column=1)

la = Label(root, text="hi")
la.grid(row=1, column=0)

b2.bind("", callback)

root.mainloop()

Кстати: вы можете использовать Button(..., command=callback), но удалить event из def callback()

from tkinter import *
from PIL import ImageTk, Image
import subprocess

def callback():
    subprocess.call("wget https://blog.furas.pl/theme/images/me/furas.png", shell=True)
    img = ImageTk.PhotoImage(Image.open("furas.png"))
    la.configure(image=img)
    la.image = img

root = Tk()
root.title("My app")
root.geometry("680x500+0+0")

b1 = Button(root, text="b1", bg="red")
b1.grid(row=0, column=0)

b2 = Button(root, text="b2", bg="blue", command=callback)
b2.grid(row=0, column=1)

la = Label(root, text="hi")
la.grid(row=1, column=0)

root.mainloop()

РЕДАКТИРОВАТЬ: вместо wget вы можете использовать стандартный модуль Python urllib и функцию urllib.request.urlretrive()

from tkinter import *
from PIL import ImageTk, Image
import urllib.request

def callback():
    urllib.request.urlretrieve("https://blog.furas.pl/theme/images/me/furas.png", "furas.png")
    img = ImageTk.PhotoImage(Image.open("furas.png"))
    la.configure(image=img)
    la.image = img

root = Tk()
root.title("My app")
root.geometry("680x500+0+0")

b1 = Button(root, text="b1", bg="red")
b1.grid(row=0, column=0)

b2 = Button(root, text="b2", bg="blue", command=callback)
b2.grid(row=0, column=1)

la = Label(root, text="hi")
la.grid(row=1, column=0)

root.mainloop()

8
задан David Z 19 February 2009 в 17:54
поделиться

8 ответов

Первый подход прост. Также достаточно, если Вы ожидаете, что загрузка будет сбалансирована равномерно по потокам. В некоторых случаях особенно если сложность bin_index является очень иждивенцем на значениях параметров, один из потоков мог закончиться с намного более тяжелой задачей, чем остальные.Помните: задача закончена, когда последние потоки заканчиваются.

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

Обратите внимание, что у Вас могут быть проблемы, помещая вычисления в отдельные потоки. Удостоверьтесь, что bin_index работает правильно, когда несколько потоков выполняют его одновременно. Остерегайтесь использования глобальных или статических переменных для промежуточных результатов.

Кроме того, "гистограмма [bin_index (i1, i2, i3, i4)] + = 1" могла быть прервана другим потоком, заставив результат быть неправильной (если присвоение выбирает значение, увеличивает его и хранит получающееся значение в массиве). Вы могли представить локальную гистограмму для каждого потока и объединить результаты к единственной гистограмме, когда все потоки закончились. Вы могли также удостовериться, что только один поток изменяет гистограмму одновременно, но это может заставить потоки блокировать друг друга большую часть времени.

2
ответ дан 5 December 2019 в 19:03
поделиться

Первый подход достаточно. Никакая потребность в сложности здесь. Если Вы начинаете играть со взаимными исключениями, Вы рискуете делать трудно для обнаружения ошибок.

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

2
ответ дан 5 December 2019 в 19:03
поделиться

Насколько я понимаю OpenMP был сделан только, для какого Вы пытаетесь сделать, хотя я должен признать, что еще не использовал его сам. В основном это, кажется, сводится к только включая заголовок и добавление пункта прагмы.

Вы могли, вероятно, также пользоваться Библиотекой Стандартных блоков Потока Intel.

2
ответ дан 5 December 2019 в 19:03
поделиться

Если Вы никогда не кодировали приложение мультипотока, я пустой Вы для начала с OpenMP:

  • библиотека теперь включена в gcc по умолчанию
  • это очень просто в использовании

В Вашем примере Вам придется просто добавить эту прагму:

#pragma omp parallel shared(histogram)
{
for (int i1 = 0; i1 < N; i1++)
  for (int i2 = 0; i2 < N; i2++)
    for (int i3 = 0; i3 < N; i3++)
      for (int i4 = 0; i4 < N; i4++)
        histogram[bin_index(i1, i2, i3, i4)] += 1;
}

С этой прагмой компилятор добавит некоторую инструкцию создать потоки, запустить их, добавить некоторые взаимные исключения вокруг доступов к histogram переменная и т.д... Существует много опций, но четко определенная прагма делает всю работу для Вас. В основном простота зависит от зависимости по данным.

Конечно, результат не должен быть оптимальным, как будто Вы кодировали все вручную. Но если у Вас нет проблемы выравнивания нагрузки, Вы, возможно, могли бы приблизиться 2x, убыстряются. На самом деле это - только запись в матрице без пространственной зависимости в нем.

2
ответ дан 5 December 2019 в 19:03
поделиться

Я сделал бы что-то вроде этого:

void HistogramThread(int i1, Action<int[]> HandleResults)
{
    int[] histogram = new int[HistogramSize];

    for (int i2 = 0; i2 < N; i2++)
       for (int i3 = 0; i3 < N; i3++)
          for (int i4 = 0; i4 < N; i4++)
             histogram[bin_index(i1, i2, i3, i4)] += 1;

    HandleResults(histogram);
}

int[] CalculateHistogram()
{
    int[] histogram = new int[HistogramSize];

    ThreadPool pool; // I don't know syntax off the top of my head
    for (int i1=0; i1<N; i1++)
    {
       pool.AddNewThread(HistogramThread, i1, delegate(int[] h)
       {
           lock (histogram)
           {
               for (int i=0; i<HistogramSize; i++)
                   histogram[i] += h[i];
           }
       });
    }
    pool.WaitForAllThreadsToFinish();

    return histogram;
}

Таким образом, Вы не должны совместно использовать память до конца.

1
ответ дан 5 December 2019 в 19:03
поделиться

Если Вы когда-нибудь делаете это в.NET, используйте Параллельные Расширения.

0
ответ дан 5 December 2019 в 19:03
поделиться

Если Вы хотите написать многопоточный код перемалывания чисел (и Вы собираетесь быть выполнением большого количества его в будущем), я предложил бы, чтобы Вы смотрели на использование функционального языка как OCaml или Haskell.

Из-за отсутствия побочных эффектов и отсутствия общего состояния на функциональных языках (хорошо, главным образом) то, чтобы заставлять Ваш код натыкаться на несколько потоков НАМНОГО легче. Плюс, Вы, вероятно, найдете, что заканчиваете с намного меньшим количеством кода.

0
ответ дан 5 December 2019 в 19:03
поделиться

Я соглашаюсь с Sharptooth, что Ваш первый подход походит на единственный вероятный.

Ваше единственное потоковое приложение непрерывно присваивает памяти. Для получения любого ускорения несколько потоков должны были бы также непрерывно присваивать памяти. Если бы только один поток присваивается за один раз, Вы не получили бы ускорения вообще. Таким образом, если бы Ваши присвоения охраняют, целое осуществление перестало бы работать.

Это было бы опасным подходом начиная с Вас присваивающий общей памяти без защиты. Но это, кажется, стоит опасности (если x2 ускорение имеет значение). Если можно быть уверены, что все значения bin_index (i1, i2, i3, i4) отличаются в подразделении цикла, то это должно работать, так как присваивание массива было бы к различные местоположения в общей памяти. Однако, всегда нужно смотреть и трудно на подходы как это.

Я предполагаю, что Вы также произвели бы тестовую задачу для сравнения результатов этих двух версий.

Править:

Смотря на Ваш bin_index (i1, i2, i3, i4), я подозреваю, что Ваш процесс не мог быть параллелизирован без значительного усилия.

Единственный способ разделить работу вычисления в Вашем цикле состоит в том, чтобы, снова, быть верным, что Ваши потоки получат доступ к тем же областям в памяти. Однако похоже, что bin_index (i1, i2, i3, i4), вероятно, повторит значения довольно часто. Вы могли бы разделить повторение на условия, где bin_index выше, чем сокращение и где это ниже, чем сокращение. Или Вы могли разделить его произвольно и видеть, реализован ли инкремент атомарно. Но любой сложный подход поточной обработки вряд ли может обеспечивать улучшение, если у Вас может только быть два ядра для работы с запуститься с.

0
ответ дан 5 December 2019 в 19:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: