Майские праздники не прошли даром: на пару дней я основательно засел за Python и написал собственный лаунчер. Зачем? Он нужен для того, чтобы не привязывать игру к конкретной игровой платформе. В моем случае, я использую GameJolt, но такой подход работает для любого сервиса. Лаунчер служит посредником между игрой и API площадки. Все, что нужно делать игре — это сообщать лаунчеру о событиях наподобие «игрок получил такую-то ачивку». Лаунчер, в свою очередь, передает эти данные игровому сервису. Если надо переехать на другой сервис, достаточно просто обновить лаунчер, а игру патчить не придется — это удобно и экономит массу времени.
(далее…)parallelism
Распараллеливание обработки изображений
API dlib.image позволяет создавать фильтры, которые легко распараллеливать на несколько процессоров. Изображение условно разбивается на несколько блоков заданного размера, которые затем обрабатываются фильтром через std.parallelism.
import std.parallelism;
import dlib.functional.range;
import dlib.image.image;
struct Block
{
uint x1, y1;
uint x2, y2;
}
alias Range!uint PixRange;
void parallelFilter(
SuperImage img,
void delegate(PixRange blockRow, PixRange blockCol) ffunc,
uint bw = 100,
uint bh = 100)
{
if (bw > img.width)
bw = img.width;
if (bh > img.height)
bh = img.height;
uint numBlocksX = img.width / bw + ((img.width % bw) > 0);
uint numBlocksY = img.height / bh + ((img.height % bh) > 0);
Block[] blocks = new Block[numBlocksX * numBlocksY];
foreach(x; 0..numBlocksX)
foreach(y; 0..numBlocksY)
{
uint bx = x * bw;
uint by = y * bh;
uint bw1 = bw;
uint bh1 = bh;
if ((img.width - bx) < bw)
bw1 = img.width - bx;
if ((img.height - by) < bh)
bh1 = img.height - by;
blocks[y * numBlocksX + x] = Block(bx, by, bx + bw1, by + bh1);
}
foreach(i, ref b; taskPool.parallel(blocks))
{
ffunc(range!uint(b.x1, b.x2),
range!uint(b.y1, b.y2));
}
}
Пример (закрашивание сплошным цветом):
SuperImage filterTestMultithreaded(SuperImage img)
{
auto res = img.dup;
img.parallelFilter((PixRange row, PixRange col)
{
foreach(x; row)
foreach(y; col)
{
res[x, y] = hsv(180.0f, 1.0f, 0.5f);
}
});
return res;
}
Для сравнения — однопоточный вариант:
SuperImage filterTestSinglethreaded(SuperImage img)
{
auto res = img.dup;
foreach(x; img.row)
foreach(y; img.col)
{
res[x, y] = hsv(180.0f, 1.0f, 0.5f);
}
return res;
}
На двухъядерном Intel Dual Core T2390 (1.86 ГГц) многопоточный вариант показывает прирост производительности на 70%.