Understanding Parallelize methodsWhy does my attempt at parallelization not work?Parallelize...
Network helper class with retry logic on failure
Obtaining the intermediate solutions in AMPL
How many US airports have 4 or more parallel runways?
Does Norwegian overbook flights?
Can I get temporary health insurance while moving to the US?
Non-visual Computers - thoughts?
How do the Etherealness and Banishment spells interact?
How many String objects would be created when concatenating multiple Strings?
Can a Rogue PC teach an NPC to perform Sneak Attack?
Papers on arXiv solving the same problem at the same time
Is "The life is beautiful" incorrect or just very non-idiomatic?
Where was Carl Sagan working on a plan to detonate a nuke on the Moon? Where was he applying when he leaked it?
How do I prevent other wifi networks from showing up on my computer?
I don't have the theoretical background in my PhD topic. I can't justify getting the degree
Are the A380 engines interchangeable (given they are not all equipped with reverse)?
Read file lines into shell line separated by space
Algorithms vs LP or MIP
How do you harvest carrots in creative mode?
Can RMSE and MAE have the same value?
What should come first—characters or plot?
Is MOSFET active device?
'Us students' - Does this apposition need a comma?
Why do banks “park” their money at the European Central Bank?
Would the Republic of Ireland and Northern Ireland be interested in reuniting?
Understanding Parallelize methods
Why does my attempt at parallelization not work?Parallelize plottingParallelize[Mapindexed[]], level={-1}? Sal Mangano's 《Cookbook》Methods Available for Derivative Pricing in Mathematica?Search/query the documentation programmaticallyWhy can't I parallelize this code
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}
$begingroup$
In the documentation page for Parallelize, we find the methods that can be used. I do not quite understand the difference between Method->"CoarsestGrained" and Method->"FinestGrained", can anyone explain it?
performance-tuning parallelization documentation function-comparison
$endgroup$
add a comment |
$begingroup$
In the documentation page for Parallelize, we find the methods that can be used. I do not quite understand the difference between Method->"CoarsestGrained" and Method->"FinestGrained", can anyone explain it?
performance-tuning parallelization documentation function-comparison
$endgroup$
add a comment |
$begingroup$
In the documentation page for Parallelize, we find the methods that can be used. I do not quite understand the difference between Method->"CoarsestGrained" and Method->"FinestGrained", can anyone explain it?
performance-tuning parallelization documentation function-comparison
$endgroup$
In the documentation page for Parallelize, we find the methods that can be used. I do not quite understand the difference between Method->"CoarsestGrained" and Method->"FinestGrained", can anyone explain it?
performance-tuning parallelization documentation function-comparison
performance-tuning parallelization documentation function-comparison
edited yesterday
Szabolcs
171k18 gold badges466 silver badges996 bronze badges
171k18 gold badges466 silver badges996 bronze badges
asked yesterday
mattiav27mattiav27
2,3972 gold badges16 silver badges34 bronze badges
2,3972 gold badges16 silver badges34 bronze badges
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
$begingroup$
Suppose you are using ParallelMap on a list of 16 elements, such as Range[16], and that you have 4 kernels.
Items from the list are sent to subkernels in groups. CoarsestGrained means that the group sizes are maximized. Thus, the groups would be sent as
{1,2,3,4}to kernel 1
{5,6,7,8}to kernel 2
{9,10,11,12}to kernel 3
{13,14,15,16}to kernel 4
Now suppose that processing small numbers (1,2,...) is very fast, but processing larger numbers (..., 15, 16) is very slow. Then kernel 1 (which has all the quick computations) would finish quickly, and kernel 4 (which has all the slow ones) would run for a long time. The time during which all 4 kernels are simultaneously active would be short.
The solution is to minimize the group sizes, i.e. use FinestGrained. First, we send
{1}to kernel 1
{2}to kernel 2
{3}to kernel 3
{4}to kernel 4
Then as soon as a kernel is finished with its initially assigned group, we send the next group, i.e. {5}, to it. And so on.
With FinestGrained, all available kernels will be working in parallel for a longer duration.
Why would you ever want to use CoarsestGrained then? It's because in this example CoarsestGrained required 4 communications between the main kernel and subkernels. FinestGrained required 16 communications. Each communication carries an overhead. If this overhead is comparable to (or larger than) the time needed to process a single element from the list, then it will significantly increase the computation time.
To set a good balance, we can also set the group sizes explicitly, using "ItemsPerEvaluation" -> groupSize.
Examples
I ran the following examples on a 4-core CPU with 4 subkernels.
When to use FinestGrained
When each item takes relatively long to evaluate (much longer than the communication overhead), and some items take much longer to evaluate than others, then it makes sense to use small group sizes. The following example will also annotate each item with the ID of the kernel on which it was processed.
ParallelMap[(Pause[#]; Labeled[Framed[#], $KernelID]) &, Range[16],
Method -> "CoarsestGrained"] // AbsoluteTiming

ParallelMap[(Pause[#]; Labeled[Framed[#], $KernelID]) &, Range[16],
Method -> "FinestGrained"] // AbsoluteTiming

When to use CoarsestGrained
When each evaluation is very fast, taking less time than the communication overhead, then it makes sense to use large group sizes.
The following example is quite extreme, because squaring a number takes much, much less time than sending an expression to a subkernel.
array = RandomReal[1, 10000];
ParallelMap[#^2 &, array,
Method -> "CoarsestGrained"]; // AbsoluteTiming
(* {0.016309, Null} *)
ParallelMap[#^2 &, array,
Method -> "FinestGrained"]; // AbsoluteTiming
(* {4.85315, Null} *)
$endgroup$
add a comment |
$begingroup$
As far as I got it, Method->"CoarsGrained" devides the overall task into a small number of jobs (e.g. one job per parallel kernel). The required data for each kernel is sent in the beginning and then the kernels can work independently of each other (at least in an optimal configuration). In the end, the parallel kernels send their results to the main kernel and the latter generates the output. This strategy minimizes communication overhead during the computation, but if the jobs need different amounts of time (this can happen, e.g., when you compute different integrals that use local refinements that stops after a varying number of iterations), this can lead to a waste of time (e.g., if all jobs are finished and only the last job runs on a single kernel/core, the main kernel (and thus the user) will have to wait for the last parallel kernel to finish).
In contrast Method->"FinestGrained" uses probably something like a queue: Many small jobs are created (e.g., one for each iterator in a ParallelDo loop). Then the jobs are distributed one by one according the order in the queue; if a parallel kernel has finished a job, it asks the "master kernel" for a new one, gets send the required data, and starts the new job and so on ... until all jobs have been finished. The problem here is that a lot of communication happens. And there is also a lot potential for delay.
Which strategy works best really depends on the problem at hand.
$endgroup$
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "387"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f204177%2funderstanding-parallelize-methods%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Suppose you are using ParallelMap on a list of 16 elements, such as Range[16], and that you have 4 kernels.
Items from the list are sent to subkernels in groups. CoarsestGrained means that the group sizes are maximized. Thus, the groups would be sent as
{1,2,3,4}to kernel 1
{5,6,7,8}to kernel 2
{9,10,11,12}to kernel 3
{13,14,15,16}to kernel 4
Now suppose that processing small numbers (1,2,...) is very fast, but processing larger numbers (..., 15, 16) is very slow. Then kernel 1 (which has all the quick computations) would finish quickly, and kernel 4 (which has all the slow ones) would run for a long time. The time during which all 4 kernels are simultaneously active would be short.
The solution is to minimize the group sizes, i.e. use FinestGrained. First, we send
{1}to kernel 1
{2}to kernel 2
{3}to kernel 3
{4}to kernel 4
Then as soon as a kernel is finished with its initially assigned group, we send the next group, i.e. {5}, to it. And so on.
With FinestGrained, all available kernels will be working in parallel for a longer duration.
Why would you ever want to use CoarsestGrained then? It's because in this example CoarsestGrained required 4 communications between the main kernel and subkernels. FinestGrained required 16 communications. Each communication carries an overhead. If this overhead is comparable to (or larger than) the time needed to process a single element from the list, then it will significantly increase the computation time.
To set a good balance, we can also set the group sizes explicitly, using "ItemsPerEvaluation" -> groupSize.
Examples
I ran the following examples on a 4-core CPU with 4 subkernels.
When to use FinestGrained
When each item takes relatively long to evaluate (much longer than the communication overhead), and some items take much longer to evaluate than others, then it makes sense to use small group sizes. The following example will also annotate each item with the ID of the kernel on which it was processed.
ParallelMap[(Pause[#]; Labeled[Framed[#], $KernelID]) &, Range[16],
Method -> "CoarsestGrained"] // AbsoluteTiming

ParallelMap[(Pause[#]; Labeled[Framed[#], $KernelID]) &, Range[16],
Method -> "FinestGrained"] // AbsoluteTiming

When to use CoarsestGrained
When each evaluation is very fast, taking less time than the communication overhead, then it makes sense to use large group sizes.
The following example is quite extreme, because squaring a number takes much, much less time than sending an expression to a subkernel.
array = RandomReal[1, 10000];
ParallelMap[#^2 &, array,
Method -> "CoarsestGrained"]; // AbsoluteTiming
(* {0.016309, Null} *)
ParallelMap[#^2 &, array,
Method -> "FinestGrained"]; // AbsoluteTiming
(* {4.85315, Null} *)
$endgroup$
add a comment |
$begingroup$
Suppose you are using ParallelMap on a list of 16 elements, such as Range[16], and that you have 4 kernels.
Items from the list are sent to subkernels in groups. CoarsestGrained means that the group sizes are maximized. Thus, the groups would be sent as
{1,2,3,4}to kernel 1
{5,6,7,8}to kernel 2
{9,10,11,12}to kernel 3
{13,14,15,16}to kernel 4
Now suppose that processing small numbers (1,2,...) is very fast, but processing larger numbers (..., 15, 16) is very slow. Then kernel 1 (which has all the quick computations) would finish quickly, and kernel 4 (which has all the slow ones) would run for a long time. The time during which all 4 kernels are simultaneously active would be short.
The solution is to minimize the group sizes, i.e. use FinestGrained. First, we send
{1}to kernel 1
{2}to kernel 2
{3}to kernel 3
{4}to kernel 4
Then as soon as a kernel is finished with its initially assigned group, we send the next group, i.e. {5}, to it. And so on.
With FinestGrained, all available kernels will be working in parallel for a longer duration.
Why would you ever want to use CoarsestGrained then? It's because in this example CoarsestGrained required 4 communications between the main kernel and subkernels. FinestGrained required 16 communications. Each communication carries an overhead. If this overhead is comparable to (or larger than) the time needed to process a single element from the list, then it will significantly increase the computation time.
To set a good balance, we can also set the group sizes explicitly, using "ItemsPerEvaluation" -> groupSize.
Examples
I ran the following examples on a 4-core CPU with 4 subkernels.
When to use FinestGrained
When each item takes relatively long to evaluate (much longer than the communication overhead), and some items take much longer to evaluate than others, then it makes sense to use small group sizes. The following example will also annotate each item with the ID of the kernel on which it was processed.
ParallelMap[(Pause[#]; Labeled[Framed[#], $KernelID]) &, Range[16],
Method -> "CoarsestGrained"] // AbsoluteTiming

ParallelMap[(Pause[#]; Labeled[Framed[#], $KernelID]) &, Range[16],
Method -> "FinestGrained"] // AbsoluteTiming

When to use CoarsestGrained
When each evaluation is very fast, taking less time than the communication overhead, then it makes sense to use large group sizes.
The following example is quite extreme, because squaring a number takes much, much less time than sending an expression to a subkernel.
array = RandomReal[1, 10000];
ParallelMap[#^2 &, array,
Method -> "CoarsestGrained"]; // AbsoluteTiming
(* {0.016309, Null} *)
ParallelMap[#^2 &, array,
Method -> "FinestGrained"]; // AbsoluteTiming
(* {4.85315, Null} *)
$endgroup$
add a comment |
$begingroup$
Suppose you are using ParallelMap on a list of 16 elements, such as Range[16], and that you have 4 kernels.
Items from the list are sent to subkernels in groups. CoarsestGrained means that the group sizes are maximized. Thus, the groups would be sent as
{1,2,3,4}to kernel 1
{5,6,7,8}to kernel 2
{9,10,11,12}to kernel 3
{13,14,15,16}to kernel 4
Now suppose that processing small numbers (1,2,...) is very fast, but processing larger numbers (..., 15, 16) is very slow. Then kernel 1 (which has all the quick computations) would finish quickly, and kernel 4 (which has all the slow ones) would run for a long time. The time during which all 4 kernels are simultaneously active would be short.
The solution is to minimize the group sizes, i.e. use FinestGrained. First, we send
{1}to kernel 1
{2}to kernel 2
{3}to kernel 3
{4}to kernel 4
Then as soon as a kernel is finished with its initially assigned group, we send the next group, i.e. {5}, to it. And so on.
With FinestGrained, all available kernels will be working in parallel for a longer duration.
Why would you ever want to use CoarsestGrained then? It's because in this example CoarsestGrained required 4 communications between the main kernel and subkernels. FinestGrained required 16 communications. Each communication carries an overhead. If this overhead is comparable to (or larger than) the time needed to process a single element from the list, then it will significantly increase the computation time.
To set a good balance, we can also set the group sizes explicitly, using "ItemsPerEvaluation" -> groupSize.
Examples
I ran the following examples on a 4-core CPU with 4 subkernels.
When to use FinestGrained
When each item takes relatively long to evaluate (much longer than the communication overhead), and some items take much longer to evaluate than others, then it makes sense to use small group sizes. The following example will also annotate each item with the ID of the kernel on which it was processed.
ParallelMap[(Pause[#]; Labeled[Framed[#], $KernelID]) &, Range[16],
Method -> "CoarsestGrained"] // AbsoluteTiming

ParallelMap[(Pause[#]; Labeled[Framed[#], $KernelID]) &, Range[16],
Method -> "FinestGrained"] // AbsoluteTiming

When to use CoarsestGrained
When each evaluation is very fast, taking less time than the communication overhead, then it makes sense to use large group sizes.
The following example is quite extreme, because squaring a number takes much, much less time than sending an expression to a subkernel.
array = RandomReal[1, 10000];
ParallelMap[#^2 &, array,
Method -> "CoarsestGrained"]; // AbsoluteTiming
(* {0.016309, Null} *)
ParallelMap[#^2 &, array,
Method -> "FinestGrained"]; // AbsoluteTiming
(* {4.85315, Null} *)
$endgroup$
Suppose you are using ParallelMap on a list of 16 elements, such as Range[16], and that you have 4 kernels.
Items from the list are sent to subkernels in groups. CoarsestGrained means that the group sizes are maximized. Thus, the groups would be sent as
{1,2,3,4}to kernel 1
{5,6,7,8}to kernel 2
{9,10,11,12}to kernel 3
{13,14,15,16}to kernel 4
Now suppose that processing small numbers (1,2,...) is very fast, but processing larger numbers (..., 15, 16) is very slow. Then kernel 1 (which has all the quick computations) would finish quickly, and kernel 4 (which has all the slow ones) would run for a long time. The time during which all 4 kernels are simultaneously active would be short.
The solution is to minimize the group sizes, i.e. use FinestGrained. First, we send
{1}to kernel 1
{2}to kernel 2
{3}to kernel 3
{4}to kernel 4
Then as soon as a kernel is finished with its initially assigned group, we send the next group, i.e. {5}, to it. And so on.
With FinestGrained, all available kernels will be working in parallel for a longer duration.
Why would you ever want to use CoarsestGrained then? It's because in this example CoarsestGrained required 4 communications between the main kernel and subkernels. FinestGrained required 16 communications. Each communication carries an overhead. If this overhead is comparable to (or larger than) the time needed to process a single element from the list, then it will significantly increase the computation time.
To set a good balance, we can also set the group sizes explicitly, using "ItemsPerEvaluation" -> groupSize.
Examples
I ran the following examples on a 4-core CPU with 4 subkernels.
When to use FinestGrained
When each item takes relatively long to evaluate (much longer than the communication overhead), and some items take much longer to evaluate than others, then it makes sense to use small group sizes. The following example will also annotate each item with the ID of the kernel on which it was processed.
ParallelMap[(Pause[#]; Labeled[Framed[#], $KernelID]) &, Range[16],
Method -> "CoarsestGrained"] // AbsoluteTiming

ParallelMap[(Pause[#]; Labeled[Framed[#], $KernelID]) &, Range[16],
Method -> "FinestGrained"] // AbsoluteTiming

When to use CoarsestGrained
When each evaluation is very fast, taking less time than the communication overhead, then it makes sense to use large group sizes.
The following example is quite extreme, because squaring a number takes much, much less time than sending an expression to a subkernel.
array = RandomReal[1, 10000];
ParallelMap[#^2 &, array,
Method -> "CoarsestGrained"]; // AbsoluteTiming
(* {0.016309, Null} *)
ParallelMap[#^2 &, array,
Method -> "FinestGrained"]; // AbsoluteTiming
(* {4.85315, Null} *)
answered yesterday
SzabolcsSzabolcs
171k18 gold badges466 silver badges996 bronze badges
171k18 gold badges466 silver badges996 bronze badges
add a comment |
add a comment |
$begingroup$
As far as I got it, Method->"CoarsGrained" devides the overall task into a small number of jobs (e.g. one job per parallel kernel). The required data for each kernel is sent in the beginning and then the kernels can work independently of each other (at least in an optimal configuration). In the end, the parallel kernels send their results to the main kernel and the latter generates the output. This strategy minimizes communication overhead during the computation, but if the jobs need different amounts of time (this can happen, e.g., when you compute different integrals that use local refinements that stops after a varying number of iterations), this can lead to a waste of time (e.g., if all jobs are finished and only the last job runs on a single kernel/core, the main kernel (and thus the user) will have to wait for the last parallel kernel to finish).
In contrast Method->"FinestGrained" uses probably something like a queue: Many small jobs are created (e.g., one for each iterator in a ParallelDo loop). Then the jobs are distributed one by one according the order in the queue; if a parallel kernel has finished a job, it asks the "master kernel" for a new one, gets send the required data, and starts the new job and so on ... until all jobs have been finished. The problem here is that a lot of communication happens. And there is also a lot potential for delay.
Which strategy works best really depends on the problem at hand.
$endgroup$
add a comment |
$begingroup$
As far as I got it, Method->"CoarsGrained" devides the overall task into a small number of jobs (e.g. one job per parallel kernel). The required data for each kernel is sent in the beginning and then the kernels can work independently of each other (at least in an optimal configuration). In the end, the parallel kernels send their results to the main kernel and the latter generates the output. This strategy minimizes communication overhead during the computation, but if the jobs need different amounts of time (this can happen, e.g., when you compute different integrals that use local refinements that stops after a varying number of iterations), this can lead to a waste of time (e.g., if all jobs are finished and only the last job runs on a single kernel/core, the main kernel (and thus the user) will have to wait for the last parallel kernel to finish).
In contrast Method->"FinestGrained" uses probably something like a queue: Many small jobs are created (e.g., one for each iterator in a ParallelDo loop). Then the jobs are distributed one by one according the order in the queue; if a parallel kernel has finished a job, it asks the "master kernel" for a new one, gets send the required data, and starts the new job and so on ... until all jobs have been finished. The problem here is that a lot of communication happens. And there is also a lot potential for delay.
Which strategy works best really depends on the problem at hand.
$endgroup$
add a comment |
$begingroup$
As far as I got it, Method->"CoarsGrained" devides the overall task into a small number of jobs (e.g. one job per parallel kernel). The required data for each kernel is sent in the beginning and then the kernels can work independently of each other (at least in an optimal configuration). In the end, the parallel kernels send their results to the main kernel and the latter generates the output. This strategy minimizes communication overhead during the computation, but if the jobs need different amounts of time (this can happen, e.g., when you compute different integrals that use local refinements that stops after a varying number of iterations), this can lead to a waste of time (e.g., if all jobs are finished and only the last job runs on a single kernel/core, the main kernel (and thus the user) will have to wait for the last parallel kernel to finish).
In contrast Method->"FinestGrained" uses probably something like a queue: Many small jobs are created (e.g., one for each iterator in a ParallelDo loop). Then the jobs are distributed one by one according the order in the queue; if a parallel kernel has finished a job, it asks the "master kernel" for a new one, gets send the required data, and starts the new job and so on ... until all jobs have been finished. The problem here is that a lot of communication happens. And there is also a lot potential for delay.
Which strategy works best really depends on the problem at hand.
$endgroup$
As far as I got it, Method->"CoarsGrained" devides the overall task into a small number of jobs (e.g. one job per parallel kernel). The required data for each kernel is sent in the beginning and then the kernels can work independently of each other (at least in an optimal configuration). In the end, the parallel kernels send their results to the main kernel and the latter generates the output. This strategy minimizes communication overhead during the computation, but if the jobs need different amounts of time (this can happen, e.g., when you compute different integrals that use local refinements that stops after a varying number of iterations), this can lead to a waste of time (e.g., if all jobs are finished and only the last job runs on a single kernel/core, the main kernel (and thus the user) will have to wait for the last parallel kernel to finish).
In contrast Method->"FinestGrained" uses probably something like a queue: Many small jobs are created (e.g., one for each iterator in a ParallelDo loop). Then the jobs are distributed one by one according the order in the queue; if a parallel kernel has finished a job, it asks the "master kernel" for a new one, gets send the required data, and starts the new job and so on ... until all jobs have been finished. The problem here is that a lot of communication happens. And there is also a lot potential for delay.
Which strategy works best really depends on the problem at hand.
edited yesterday
answered yesterday
Henrik SchumacherHenrik Schumacher
67.7k5 gold badges96 silver badges186 bronze badges
67.7k5 gold badges96 silver badges186 bronze badges
add a comment |
add a comment |
Thanks for contributing an answer to Mathematica Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f204177%2funderstanding-parallelize-methods%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown