2014-09-19 3 views
1

URL 이미지 목록을 가지고 있으며 각 이미지를 다운로드하고 저장하려고합니다. 불행히도, 나는 힙 공간이 부족하여 Out of Memory 예외를 계속 수신합니다. 마지막 시도는 두 개의 이미지를 저장 한 다음 "33554464 바이트를 할당하려고했습니다."라는 힙 공간을 낭비했습니다.이미지 목록을 올바르게 다운로드하고 저장하려면 어떻게해야합니까?

내 코드는 다음과 같습니다. 논리는 올바른 것처럼 보이지만 비동기 호출이 잘못되었을 수 있습니다. 다운로드를 순차적으로 수행하도록 조정해야합니까? 아니면 제가 사용해야 할 또 다른 방법이 있습니까?

import 'package:http/http.dart' as http; 
import 'dart:io'; 

main() { 
    // loc is a Set of valid URLs 
    // ... 

    loc.forEach(retrieveImage) 
} 

void retrieveImage(String location) { 
    Uri uri = Uri.parse(location); 
    String name = uri.pathSegments.last; 

    print("Reading $location"); 
    http.readBytes(location).then((image) => saveImage(name, image)); 

} 

void saveImage(String name, var data) { 
    new File("${name}") 
    ..writeAsBytesSync(data); 
    print(name); 
} 

답변

2

순차적으로 다운로드하려면 Future.forEach으로 전환 할 수 있습니다. 이 컬렉션은 컬렉션을 통해 각각에 대해 함수를 실행하지만 함수가 다음으로 이동하기 전에 완료 될 때까지 기다리는 미래를 기다립니다. 이는 최종 반복이 완료되면 완료되는 미래를 반환합니다. 대신 다음

loc.forEach(retrieveImage); 

사용

Future.forEach(loc, retrieveImage); 

과의

retrieveImage 반환에게 미래를 보장 :

Future retrieveImage(String location) { 
    Uri uri = Uri.parse(location); 
    String name = uri.pathSegments.last; 

    print("Reading $location"); 
    return http.readBytes(location).then((image) => saveImage(name, image)); 
} 
+0

이것은 내 메모리 문제를 해결하기 위해 완벽하게 작동했습니다. 여러 파일을 동시에 다운로드 할 수 있도록 다시 방문하고 싶습니다. 감사. 나는 새로운 것을 배웠다. –

1

@DannyTuppeny의 문제가 해결되지 않으면 당신이 할 수있는 힙 크기를 늘리십시오. 나는 이것이이

old_gen_heap_size: 1024 (Max size of old gen heap size in MB,e.g: --old_gen_heap_size=1024 allows up to 1024MB old gen heap) 
dart --old_gen_heap_size=1024 somefile.dart 

또는

export DART_VM_OPTIONS="--old_gen_heap_size=1024" 

http://dartbug.com/13744도를 나열하지 않습니다 --new_gen_heap_size하지만 dart --print-flags을 언급하지 플래그해야한다고 생각합니다. 이것이 지원되는지, 어떤 역할을하는지는 알 수 없습니다.

코드에서 볼 수있는 문제는 모든 이미지가 거의 한 번에 다운로드되기 시작하고 수신되는 동안 힙 메모리를 사용한다는 것입니다. 또한 @DannyTupeny의 코드는 변경되지 않습니다.

이전 요청이 완료되었을 때 새 요청 만 호출하거나 파일을받은 동안 스트림을 사용하여 파일을 메모리에 버퍼링하지 않아도 동시에 다운로드 할 수있는 파일 수를 제한 할 수 있습니다 전적으로. 나는 아직이 일을하지 않았으며 적어도 일요일까지 그것을 들여다 볼 시간이 없을 것이다. 그러나 어쩌면 다른 누군가가 그런 시도에 대해 더 많은 것을 제공 할 수있다.

메모리에 전체 파일을 버퍼링하지 않고 들어오는 데이터를 파일로 직접 리디렉션하려면 작동해야하지만 메모리 부족 문제를 재현 할 수 없어 확실히 말할 수는 없습니다.

import 'dart:io' as io; 
import 'dart:async' as async; 
import 'package:path/path.dart' as path; 
import 'package:http/http.dart' as http; 

var images = [ 
    "https://c4.staticflickr.com/4/3880/15283361621_bc72a1fb29_z.jpg", 
    "https://c2.staticflickr.com/4/3923/15101476099_6e1087b76c_h.jpg", 
    "https://c2.staticflickr.com/4/3899/15288834802_073d2af478_z.jpg", 
    "https://c4.staticflickr.com/4/3880/15283361621_bc72a1fb29_z.jpg", 
    "https://c2.staticflickr.com/6/5575/15101869429_fa44a80e87_z.jpg", 
    "https://c1.staticflickr.com/3/2941/15100232360_03f3631c44_z.jpg", 
    "https://c1.staticflickr.com/3/2941/15269480156_a28e1c0dbb_b.jpg", 
    "https://c2.staticflickr.com/4/3907/15103503127_195ffcd5c0_z.jpg", 
    "https://c2.staticflickr.com/6/5595/15265903986_a3210505f4_c.jpg", 
    "https://c2.staticflickr.com/6/5567/15100857617_9926f2a189_z.jpg", 
    "https://c1.staticflickr.com/3/2941/15100542247_6e9c3f13ae_z.jpg", 
    "https://c2.staticflickr.com/4/3852/15099895539_cf43a904a5_z.jpg" 
]; 

main() { 
    var futures = <async.Future>[]; 

    images.forEach((url) { 
    futures.add(new http.Request('GET', Uri.parse(url)) 
    .send().then((response) { 
     var f = new io.File(path.basename(url)); 
     var sink = f.openWrite(); 
     sink.addStream(response.stream) 
     .then((_) => sink.close()); 
    })); 
    }); 
    async.Future.wait(futures) // wait for all image downloads to be finished 
    .then((_) => print('done')); 
} 
+0

감사합니다. Streams 옵션을 직접 살펴 보았지만 혼란 스러웠습니다. @DannyTuppeny 솔루션을 시도하고 권장하는대로 힙 크기를 늘릴 것입니다.모든 다운로드가 동시에 수행되고 있으며 이는 대부분 문제 일 수 있습니다. –

+1

답변을 업데이트했습니다. –

+0

굉장합니다. 고맙습니다. 솔루션을 시험해보기 위해 코드를 리팩토링 해 보겠습니다. –

관련 문제