每个线程一个 Random 实例,由原始 Random 实例播种以获得可重复性
One Random instance per thread, seeded by the original Random instance to attain reproducibility
我需要进行 1000
次计算,每次计算都基于一个随机数。
整个 运行 需要 可重现。
在单线程环境中,我只是根据种子创建随机数并将其用于每次计算:
Random random = new Random(37);
for (Calculation c : calculations) {
c.doCalculation(r.nextInt());
}
在多线程环境中,我有 10
个线程,我有一个种子随机种子线程 Random's:
Random initRandom = new Random(37);
for (List<Calculation> p : calculationPartitions) {
final Random threadRandom = new Random(initRandom.nextLong());
executorService.submit(() -> {
for (Calculation c : p) {
c.doCalculation(threadRandom.nextInt());
}
});
}
// Merge the calculation results back in the same order as the calculationPartitions
...
这是个好主意吗?总体上它仍然是均匀分布的随机数吗?每个 threadRandom
都是由 initRandom
播种的,这不会破坏均匀分布吗?
出于可重现的原因,我无法共享 1 个全局随机数,因为某些线程可能 运行 在某些 运行 秒内比其他线程更快,因此它们不会总是以相同的顺序调用全局随机数(争用可能会导致性能下降)。
您将通过 Random 获得均匀分布的数字,但是无法保证列表中每个计算对象列表的顺序 运行 因此,如果这些然后将结果传递给共享列表顺序可能会在 运行 秒内发生变化。
具体关于均匀分布,每 10 个像素 1 个随机位置似乎没问题:
哦等等,每 1 个像素有 1 个随机位置,种子线程方法似乎更好!?在完美的均匀分布中(对于尺寸 250000),它将全黑:
左:
public class SingleRandomProof extends JFrame {
public static final int WIDTH = 500;
public static final int HEIGHT = 500;
public static final int SIZE = WIDTH * HEIGHT;
public static void main(String[] args) {
SingleRandomProof proof = new SingleRandomProof();
proof.pack();
proof.setVisible(true);
proof.doCalc();
}
private JLabel panel;
public SingleRandomProof() throws HeadlessException {
super("1 random");
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
panel = new JLabel(new ImageIcon(image));
setContentPane(panel);
}
private void doCalc() {
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
Random r = new Random(37);
for (int i = 0; i < SIZE; i++) {
int position = r.nextInt(SIZE);
g.fillRect(position % HEIGHT, position / HEIGHT, 1, 1);
}
panel.setIcon(new ImageIcon(image));
}
}
右:
public class SeededThreadRandomProof extends JFrame {
public static final int WIDTH = 500;
public static final int HEIGHT = 500;
public static final int SIZE = WIDTH * HEIGHT;
public static void main(String[] args) {
SeededThreadRandomProof proof = new SeededThreadRandomProof();
proof.pack();
proof.setVisible(true);
proof.doCalc();
}
private JLabel panel;
public SeededThreadRandomProof() throws HeadlessException {
super("10 seeded randoms");
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
panel = new JLabel(new ImageIcon(image));
setContentPane(panel);
}
private void doCalc() {
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
Random initRandom = new Random(37);
for (int j = 0; j < 10; j++) {
Random r = new Random(initRandom.nextLong());
for (int i = 0; i < SIZE / 10; i++) {
int position = r.nextInt(SIZE);
g.fillRect(position % HEIGHT, position / HEIGHT, 1, 1);
}
}
panel.setIcon(new ImageIcon(image));
}
}
我需要进行 1000
次计算,每次计算都基于一个随机数。
整个 运行 需要 可重现。
在单线程环境中,我只是根据种子创建随机数并将其用于每次计算:
Random random = new Random(37);
for (Calculation c : calculations) {
c.doCalculation(r.nextInt());
}
在多线程环境中,我有 10
个线程,我有一个种子随机种子线程 Random's:
Random initRandom = new Random(37);
for (List<Calculation> p : calculationPartitions) {
final Random threadRandom = new Random(initRandom.nextLong());
executorService.submit(() -> {
for (Calculation c : p) {
c.doCalculation(threadRandom.nextInt());
}
});
}
// Merge the calculation results back in the same order as the calculationPartitions
...
这是个好主意吗?总体上它仍然是均匀分布的随机数吗?每个 threadRandom
都是由 initRandom
播种的,这不会破坏均匀分布吗?
出于可重现的原因,我无法共享 1 个全局随机数,因为某些线程可能 运行 在某些 运行 秒内比其他线程更快,因此它们不会总是以相同的顺序调用全局随机数(争用可能会导致性能下降)。
您将通过 Random 获得均匀分布的数字,但是无法保证列表中每个计算对象列表的顺序 运行 因此,如果这些然后将结果传递给共享列表顺序可能会在 运行 秒内发生变化。
具体关于均匀分布,每 10 个像素 1 个随机位置似乎没问题:
哦等等,每 1 个像素有 1 个随机位置,种子线程方法似乎更好!?在完美的均匀分布中(对于尺寸 250000),它将全黑:
左:
public class SingleRandomProof extends JFrame {
public static final int WIDTH = 500;
public static final int HEIGHT = 500;
public static final int SIZE = WIDTH * HEIGHT;
public static void main(String[] args) {
SingleRandomProof proof = new SingleRandomProof();
proof.pack();
proof.setVisible(true);
proof.doCalc();
}
private JLabel panel;
public SingleRandomProof() throws HeadlessException {
super("1 random");
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
panel = new JLabel(new ImageIcon(image));
setContentPane(panel);
}
private void doCalc() {
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
Random r = new Random(37);
for (int i = 0; i < SIZE; i++) {
int position = r.nextInt(SIZE);
g.fillRect(position % HEIGHT, position / HEIGHT, 1, 1);
}
panel.setIcon(new ImageIcon(image));
}
}
右:
public class SeededThreadRandomProof extends JFrame {
public static final int WIDTH = 500;
public static final int HEIGHT = 500;
public static final int SIZE = WIDTH * HEIGHT;
public static void main(String[] args) {
SeededThreadRandomProof proof = new SeededThreadRandomProof();
proof.pack();
proof.setVisible(true);
proof.doCalc();
}
private JLabel panel;
public SeededThreadRandomProof() throws HeadlessException {
super("10 seeded randoms");
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
panel = new JLabel(new ImageIcon(image));
setContentPane(panel);
}
private void doCalc() {
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
Random initRandom = new Random(37);
for (int j = 0; j < 10; j++) {
Random r = new Random(initRandom.nextLong());
for (int i = 0; i < SIZE / 10; i++) {
int position = r.nextInt(SIZE);
g.fillRect(position % HEIGHT, position / HEIGHT, 1, 1);
}
}
panel.setIcon(new ImageIcon(image));
}
}