{
"cells": [
{
"cell_type": "code",
"execution_count": 9,
"id": "d959a605",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"juliaSetPixel"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\"\"\"\n",
"Computes a julia set pixel.\n",
"\"\"\"\n",
"function juliaSetPixel(z0, c)\n",
" z = z0\n",
" niter = 255\n",
" for i in 1:niter\n",
" abs2(z)> 4.0 && return (i - 1)%UInt8\n",
" z = z*z + c\n",
" end\n",
" return niter%UInt8\n",
"end\n",
"\n",
"\"\"\"\n",
"Computes a column (`j`) of the julia set image.\n",
"The result is written into the corresponding column of `pic`.\n",
"\"\"\"\n",
"function calcColumn!(pic, c, n, j)\n",
" x = -2.0 + (j-1)*4.0/(n-1)\n",
" for i in 1:n\n",
" y = -2.0 + (i-1)*4.0/(n-1)\n",
" @inbounds pic[i,j] = juliaSetPixel(x+im*y, c)\n",
" end\n",
" nothing\n",
"end\n",
"\n",
"\"\"\"\n",
"Sequential column-by-column construction of the julia set image\n",
"\"\"\"\n",
"function juliaSetCalc!(pic, c, n)\n",
" for j in 1:n\n",
" calcColumn!(pic, c, n, j)\n",
" end\n",
" nothing\n",
"end\n",
"\n",
"\"\"\"\n",
"Compute the julia set image using the method `method`.\n",
"\"\"\"\n",
"function juliaSet(method = juliaSetCalc!, extra...)\n",
" c = -0.79 + 0.15*im\n",
" n = 1000\n",
" pic = Array{UInt8,2}(undef,n,n)\n",
" method(pic, c, n, extra...)\n",
" return pic\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "660d8797",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"using Plots\n",
"\n",
"frac = juliaSet()\n",
"plot(heatmap(1:size(frac,1),1:size(frac,2), frac, color=:Spectral))"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "d2a74154",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 58.445 ms (2 allocations: 976.70 KiB)\n"
]
}
],
"source": [
"using BenchmarkTools\n",
"@btime juliaSet();"
]
},
{
"cell_type": "markdown",
"id": "645fe937",
"metadata": {},
"source": [
"## Multithreading: `@threads`"
]
},
{
"cell_type": "code",
"execution_count": 82,
"id": "737bd435",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"juliaSetCalcThread! (generic function with 1 method)"
]
},
"execution_count": 82,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import Base.Threads: @threads\n",
"\n",
"function juliaSetCalcThread!(pic, c, n)\n",
" @threads for j in 1:n\n",
" calcColumn!(pic, c, n, j)\n",
" end\n",
" return nothing\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 83,
"id": "aa45672d",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n"
]
},
"execution_count": 83,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"frac = juliaSet(juliaSetCalcThread!)\n",
"plot(heatmap(1:size(frac,1),1:size(frac,2), frac, color=:Spectral))"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "0de85d17",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 17.758 ms (35 allocations: 979.17 KiB)\n"
]
}
],
"source": [
"@btime juliaSet(juliaSetCalcThread!);"
]
},
{
"cell_type": "code",
"execution_count": 84,
"id": "f7b4f188",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"juliaSetPixel (generic function with 1 method)"
]
},
"execution_count": 84,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Turon on debugging :D\n",
"import Base.Threads: nthreads, threadid\n",
"\n",
"function calcColumn!(pic, c, n, j)\n",
" x = -2.0 + (j-1)*4.0/(n-1)\n",
" cols[j] = threadid()\n",
" for i in 1:n\n",
" y = -2.0 + (i-1)*4.0/(n-1)\n",
" @inbounds pic[i,j] = juliaSetPixel(x+im*y, c)\n",
" end\n",
" nothing\n",
"end\n",
"\n",
"function juliaSetPixel(z0, c)\n",
" z = z0\n",
" niter = 255\n",
" for i in 1:niter\n",
" niters[threadid()] += 1\n",
" abs2(z)> 4.0 && return (i - 1)%UInt8\n",
" z = z*z + c\n",
" end\n",
" return niter%UInt8\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 85,
"id": "fd485770",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n"
]
},
"execution_count": 85,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"niters = zeros(nthreads())\n",
"cols = zeros(1000)\n",
"juliaSet(juliaSetCalcThread!)\n",
"bar(niters, xlab=\"threadid\", ylab=\"# iterations\", legend=false)"
]
},
{
"cell_type": "code",
"execution_count": 156,
"id": "d6d7cf43",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n"
]
},
"execution_count": 156,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"heatmap([c for i in 1:length(cols), c in cols])"
]
},
{
"cell_type": "markdown",
"id": "43623524",
"metadata": {},
"source": [
"## Multithreading: `@spawn`"
]
},
{
"cell_type": "code",
"execution_count": 77,
"id": "c50f0e5f",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"juliaSetCalcSpawn! (generic function with 1 method)"
]
},
"execution_count": 77,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import Base.Threads: @spawn\n",
"\n",
"function juliaSetCalcSpawn!(pic, c, n)\n",
" @sync for j in 1:n\n",
" @spawn calcColumn!(pic, c, n, j)\n",
" end\n",
" return nothing\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 162,
"id": "e69b966f",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n"
]
},
"execution_count": 162,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"niters = zeros(nthreads())\n",
"cols = zeros(1000)\n",
"juliaSet(juliaSetCalcSpawn!)\n",
"bar(niters, xlab=\"threadid\", ylab=\"# iterations\", legend=false)"
]
},
{
"cell_type": "code",
"execution_count": 163,
"id": "0f01a4fc",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n"
]
},
"execution_count": 163,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"heatmap([c for i in 1:length(cols), c in cols])"
]
},
{
"cell_type": "code",
"execution_count": 164,
"id": "8f96d09a",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"juliaSetPixel (generic function with 1 method)"
]
},
"execution_count": 164,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Turn off debugging :D\n",
"function calcColumn!(pic, c, n, j)\n",
" x = -2.0 + (j-1)*4.0/(n-1)\n",
" for i in 1:n\n",
" y = -2.0 + (i-1)*4.0/(n-1)\n",
" @inbounds pic[i,j] = juliaSetPixel(x+im*y, c)\n",
" end\n",
" nothing\n",
"end\n",
"\n",
"function juliaSetPixel(z0, c)\n",
" z = z0\n",
" niter = 255\n",
" for i in 1:niter\n",
" abs2(z)> 4.0 && return (i - 1)%UInt8\n",
" z = z*z + c\n",
" end\n",
" return niter%UInt8\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 165,
"id": "92c178d4",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n"
]
},
"execution_count": 165,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"frac = juliaSet(juliaSetCalcSpawn!)\n",
"plot(heatmap(1:size(frac,1),1:size(frac,2), frac, color=:Spectral))"
]
},
{
"cell_type": "code",
"execution_count": 73,
"id": "5a63d3b1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 10.137 ms (6022 allocations: 1.38 MiB)\n"
]
}
],
"source": [
"@btime juliaSet(juliaSetCalcSpawn!);"
]
},
{
"cell_type": "markdown",
"id": "d2f699a2",
"metadata": {},
"source": [
"Based on http://www.cs.unb.ca/~aubanel/JuliaMultithreadingNotes.html."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.6.1",
"language": "julia",
"name": "julia-1.6"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.6.1"
}
},
"nbformat": 4,
"nbformat_minor": 5
}