Java 并行流无法用于将多个文件上载到aws s3
以下方法用于将文件并行上载到AWS S3,但不会进行并行处理。上传30个文件需要30秒,上传50个文件需要50秒。 我不确定为什么parallel()流在我的用例中不起作用。任何指点都将不胜感激Java 并行流无法用于将多个文件上载到aws s3,java,amazon-s3,java-8,Java,Amazon S3,Java 8,以下方法用于将文件并行上载到AWS S3,但不会进行并行处理。上传30个文件需要30秒,上传50个文件需要50秒。 我不确定为什么parallel()流在我的用例中不起作用。任何指点都将不胜感激 public ConcurrentHashMap<String, String> uploadMyFiles(MultipartFile[] files, String prefix) { ConcurrentHashMap<String, String> map = n
public ConcurrentHashMap<String, String> uploadMyFiles(MultipartFile[] files, String prefix) {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();
Stream.of(files).parallel().forEach(file -> {
String fStatus = uploadMyFile(file, prefix);
map.put(file.getOriginalFilename(), fStatus);
});
return fileStatusMap;
}
public String uploadMyFile(final MultipartFile multipartFile, String prefix) {
try {
final File file = convertMPartFileToFile(multipartFile);
uploadToMyBucket("mybucket", file, prefix);
} catch (final AwsServiceException exception) {
return exception.getMessage()
}
return "OK";
}
private File convertMPartFileToFile(final MultipartFile multipartFile) {
final File file = new File(multipartFile.getOriginalFilename());
try (final FileOutputStream outputStream = new FileOutputStream(file)) {
outputStream.write(multipartFile.getBytes());
} catch (final IOException ex) {
LOGGER.error("log error here");
}
return file;
}
private String uploadToMyBucket(final String bucket, final File file, String fileKey) {
PutObjectResponse putObjectResult = s3Client
.putObject(PutObjectRequest.builder().bucket(bucket).key(fileKey).build(), RequestBody.fromFile(file));
final URL myfileUrl = s3Client.utilities().getUrl(GetUrlRequest.builder().bucket(bucket).key(fileKey).build());
return myfileUrl.toString();
}
公共ConcurrentHashMap uploadMyFiles(多部分文件[]文件,字符串前缀){
ConcurrentHashMap=新的ConcurrentHashMap();
Stream.of(files).parallel().forEach(file->{
字符串fStatus=uploadMyFile(文件,前缀);
map.put(file.getOriginalFilename(),fStatus);
});
返回fileStatusMap;
}
公共字符串uploadMyFile(最终MultipartFile MultipartFile,字符串前缀){
试一试{
最终文件文件=convertMPartFileToFile(多部分文件);
uploadToMyBucket(“mybucket”,文件,前缀);
}捕获(最终AwsServiceException异常){
返回异常。getMessage()
}
返回“OK”;
}
私有文件convertMPartFileToFile(最终多部分文件多部分文件){
最终文件=新文件(multipartFile.getOriginalFilename());
try(final FileOutputStream outputStream=新FileOutputStream(文件)){
write(multipartFile.getBytes());
}捕获(最终IOEX){
LOGGER.error(“此处记录错误”);
}
返回文件;
}
私有字符串上传到Tomybucket(最终字符串存储桶、最终文件文件、字符串文件密钥){
PutObjectResponse putObjectResult=s3Client
.putObject(PutObjectRequest.builder().bucket(bucket).key(fileKey).build(),RequestBody.fromFile(file));
最终URL myfileUrl=s3Client.utilities().getUrl(GetUrlRequest.builder().bucket(bucket).key(fileKey.build());
返回myfileUrl.toString();
}
我建议将
TransferManager
与ExecutorService
一起使用,如下例所示
一般情况下,并行任何代码的步骤(一般情况下,AWS不起作用)
ThreadPool
,您可以将Callable
的集合提交给它进行处理集合提交到线程池的一段代码。每个可调用线程都将在线程池中的线程中执行
Future
集合中检索结果的代码段 public class S09 {
public static void main(String[] args) {
demoParallel();
}
public static void demoParallel() {
ExecutorService eService = Executors.newFixedThreadPool(5);
String[] myArr = new String[] {"A", "B", "C"};
Stream.of(myArr)
.parallel()
.map(S09::generateCallable)
.map(eService::submit)
.map(S09::obtainFuture)
.forEach(System.out::println);
}
public static void demoMethod() {}
private static Callable<String> generateCallable(final String input) {
return () -> {
System.out.println(
"I am waiting here, " + Thread.currentThread() + " for Input String " + input);
Thread.sleep(5000); // someExpensiveOperationHere
return "Return Value of " + input;
};
}
private static String obtainFuture(Future<String> futureString) {
try {
return futureString.get(10, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
e.printStackTrace();
}
return null;
}
}
公共类S09{
公共静态void main(字符串[]args){
demoParallel();
}
公共静态void demoParallel(){
ExecutorService eService=Executors.newFixedThreadPool(5);
字符串[]myArr=新字符串[]{“A”、“B”、“C”};
溪流(myArr)
.parallel()
.map(S09::GenerateCalable)
.map(电子服务::提交)
.map(S09::获取未来)
.forEach(System.out::println);
}
公共静态void demoMethod(){}
私有静态可调用generateCallable(最终字符串输入){
返回()->{
System.out.println(
“我在这里等待,”+Thread.currentThread()+”表示输入字符串“+Input);
Thread.sleep(5000);//这里有些昂贵的操作
返回“返回值”+输入;
};
}
私有静态字符串获取未来(未来未来字符串){
试一试{
返回futureString.get(10,时间单位为秒);
}捕获(InterruptedException | ExecutionException | TimeoutException e){
e、 printStackTrace();
}
返回null;
}
}
请在uploadMyFileA中完整地展示代码,但是s3句柄是否能够接收来自多个线程的请求(例如,它是否只通过一个单线程工作线程提供请求)?这是一段时间以来,我与API工作,认为有必要为一个线程本地句柄的S3Advess全代码转移管理器有一个最低限度的限制-5MB每部分除了最后一部分。在我的例子中,每个文件都小于1MB。所以技术上我不能用it@mark-多端口加载阈值和最小上载部件大小可配置OK。你认为这会提高性能吗?此外,我还需要在上传结束时返回每个文件上传的状态(失败或成功)对此有何想法?我正在尝试,但我刚刚注意到AWS SDK java2版本还不支持TransferManager,我现有的S3Client使用java2,我无法使用java2 s3客户端创建TransferManager!非常感谢。我已经试过这个代码了。我甚至使用了AWS异步客户机,并提交了他们的完整的未来。它有一点改进,但没有太多改进。请参考java示例回答中的另一个问题,并行流也可以通过在单独的线程中运行每个任务来实现相同的效果?在这种情况下,除非有人想管理线程,否则我们真的需要使用callable吗?