Multithreaded execution where order of finished Work Items is preserved

后端 未结 9 1190
无人共我
无人共我 2021-02-01 08:28

I have a flow of units of work, lets call them \"Work Items\" that are processed sequentially (for now). I\'d like to speed up processing by doing the work multithreaded.

<
9条回答
  •  -上瘾入骨i
    2021-02-01 08:58

    Reactive programming could help. During my brief experience with RxJava I found it to be intuitive and easy to work with than core language features like Future etc. Your mileage may vary. Here are some helpful starting points https://www.youtube.com/watch?v=_t06LRX0DV0

    The attached example also shows how this could be done. In the example below we have Packet's which need to be processed. They are taken through a simple trasnformation and fnally merged into one list. The output appended to this message shows that the Packets are received and transformed at different points in time but in the end they are output in the order they have been received

    import static java.time.Instant.now;
    import static rx.schedulers.Schedulers.io;
    
    import java.time.Instant;
    import java.util.List;
    import java.util.Random;
    
    import rx.Observable;
    import rx.Subscriber;
    
    public class RxApp {
    
      public static void main(String... args) throws InterruptedException {
    
        List processedPackets = Observable.range(0, 10) //
            .flatMap(i -> {
              return getPacket(i).subscribeOn(io());
            }) //
            .map(Packet::transform) //
            .toSortedList() //
            .toBlocking() //
            .single();
    
        System.out.println("===== RESULTS =====");
        processedPackets.stream().forEach(System.out::println);
      }
    
      static Observable getPacket(Integer i) {
        return Observable.create((Subscriber s) -> {
          // simulate latency
          try {
            Thread.sleep(new Random().nextInt(5000));
          } catch (Exception e) {
            e.printStackTrace();
          }
          System.out.println("packet requested for " + i);
          s.onNext(new Packet(i.toString(), now()));
          s.onCompleted();
        });
      }
    
    }
    
    
    class Packet {
      String aString;
      Instant createdOn;
    
      public Packet(String aString, Instant time) {
        this.aString = aString;
        this.createdOn = time;
      }
    
      public ProcessedPacket transform() {
        System.out.println("                          Packet being transformed " + aString);
        try {
          Thread.sleep(new Random().nextInt(5000));
        } catch (Exception e) {
          e.printStackTrace();
        }
        ProcessedPacket newPacket = new ProcessedPacket(this, now());
        return newPacket;
      }
    
      @Override
      public String toString() {
        return "Packet [aString=" + aString + ", createdOn=" + createdOn + "]";
      }
    }
    
    
    class ProcessedPacket implements Comparable {
      Packet p;
      Instant processedOn;
    
      public ProcessedPacket(Packet p, Instant now) {
        this.p = p;
        this.processedOn = now;
      }
    
      @Override
      public int compareTo(ProcessedPacket o) {
        return p.createdOn.compareTo(o.p.createdOn);
      }
    
      @Override
      public String toString() {
        return "ProcessedPacket [p=" + p + ", processedOn=" + processedOn + "]";
      }
    
    }
    

    Deconstruction

    Observable.range(0, 10) //
        .flatMap(i -> {
          return getPacket(i).subscribeOn(io());
        }) // source the input as observables on multiple threads
    
    
        .map(Packet::transform) // processing the input data 
    
        .toSortedList() // sorting to sequence the processed inputs; 
        .toBlocking() //
        .single();
    

    On one particular run Packets were received in the order 2,6,0,1,8,7,5,9,4,3 and processed in order 2,6,0,1,3,4,5,7,8,9 on different threads

    packet requested for 2
                              Packet being transformed 2
    packet requested for 6
                              Packet being transformed 6
    packet requested for 0
    packet requested for 1
                              Packet being transformed 0
    packet requested for 8
    packet requested for 7
    packet requested for 5
    packet requested for 9
                              Packet being transformed 1
    packet requested for 4
    packet requested for 3
                              Packet being transformed 3
                              Packet being transformed 4
                              Packet being transformed 5
                              Packet being transformed 7
                              Packet being transformed 8
                              Packet being transformed 9
    ===== RESULTS =====
    ProcessedPacket [p=Packet [aString=2, createdOn=2016-04-14T13:48:52.060Z], processedOn=2016-04-14T13:48:53.247Z]
    ProcessedPacket [p=Packet [aString=6, createdOn=2016-04-14T13:48:52.130Z], processedOn=2016-04-14T13:48:54.208Z]
    ProcessedPacket [p=Packet [aString=0, createdOn=2016-04-14T13:48:53.989Z], processedOn=2016-04-14T13:48:55.786Z]
    ProcessedPacket [p=Packet [aString=1, createdOn=2016-04-14T13:48:54.109Z], processedOn=2016-04-14T13:48:57.877Z]
    ProcessedPacket [p=Packet [aString=8, createdOn=2016-04-14T13:48:54.418Z], processedOn=2016-04-14T13:49:14.108Z]
    ProcessedPacket [p=Packet [aString=7, createdOn=2016-04-14T13:48:54.600Z], processedOn=2016-04-14T13:49:11.338Z]
    ProcessedPacket [p=Packet [aString=5, createdOn=2016-04-14T13:48:54.705Z], processedOn=2016-04-14T13:49:06.711Z]
    ProcessedPacket [p=Packet [aString=9, createdOn=2016-04-14T13:48:55.227Z], processedOn=2016-04-14T13:49:16.927Z]
    ProcessedPacket [p=Packet [aString=4, createdOn=2016-04-14T13:48:56.381Z], processedOn=2016-04-14T13:49:02.161Z]
    ProcessedPacket [p=Packet [aString=3, createdOn=2016-04-14T13:48:56.566Z], processedOn=2016-04-14T13:49:00.557Z]
    

提交回复
热议问题