programing

C# 비동기/대기 Java 등가물?

copysource 2022. 9. 1. 00:09
반응형

C# 비동기/대기 Java 등가물?

저는 일반 C# 개발자입니다만, 때때로 Java에서 애플리케이션을 개발하기도 합니다.C# 비동기/대기 대응 Java가 있는지 궁금합니다.간단히 말하면 자바란 무엇인가?

async Task<int> AccessTheWebAsync()
{ 
    HttpClient client = new HttpClient();
    var urlContents = await client.GetStringAsync("http://msdn.microsoft.com");
    return urlContents.Length;
}

아니요. Java에서는 비동기/대기 또는 v5 이전 C#에는 없습니다.

국가 기계를 배후에서 만드는 것은 상당히 복잡한 언어 기능입니다.

Java에서는 비동기/컨커런시에 대한 언어 지원이 비교적 적지만java.util.concurrent패키지에는 이와 관련된 유용한 클래스가 많이 포함되어 있습니다.(태스크 병렬 라이브러리와는 완전히 동일하지는 않지만 거의 비슷합니다.)

await는, 하면, 합니다( 「 」 、 「 」 、 「 」 、 「 」 、 「 」 。client.GetStringAsync(...)

그래서, 가장 가까운 근사치로서CompletableFuture<T>은 .(Java 8) .net에 ).Task<TResult>를 비동기적으로 기반의 솔루션으로 HTTP 요구를 비동기적으로 처리합니다.

2016년 5월 25일 Abril 13일에 출시된 AsyncHttpClient v.2로 업데이트됨:

8의 와 동등합니다.AccessTheWebAsync()

CompletableFuture<Integer> AccessTheWebAsync()
{
    AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient();
    return asyncHttpClient
       .prepareGet("http://msdn.microsoft.com")
       .execute()
       .toCompletableFuture()
       .thenApply(Response::getResponseBody)
       .thenApply(String::length);
}

이 사용법은 "완료 테이블을 얻는 방법"에 대한 답변에서 인용한 것입니다.비동기 HTTP 클라이언트 요청의 미래?2016년 Abril 13일에 출시된 Abril Http Client 버전2에서 제공되는 새로운 API에 따르면 이미 Abril 13에 대한 본질적인 지원이 있습니다.CompletableFuture<T>.

AsyncHttpClient 버전1을 사용한 원래 응답:

이를 위해 두 가지 방법이 있습니다.

  • 를 사용하고 , 저는 을 IO라고 .AccessTheWebAsyncNio하지만,AsyncCompletionHandler는 추상 클래스(기능 인터페이스의 개요)입니다.lamda를 인수로 전달할 수 없습니다.그래서 그것은 익명 수업의 구문 때문에 불가피하게 장황하게 나타난다.단, 이 솔루션은 지정된 C# 예의 실행 흐름에 가장 가깝습니다.

  • 두 번째는 약간 덜 상세하지만 최종적으로 스레드를 차단하는 새로운 태스크를 제출합니다.f.get()응답이 완료될 때까지 계속합니다.

번째 접근법, 보다 상세하지만 비블로킹:

static CompletableFuture<Integer> AccessTheWebAsyncNio(){
    final AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
    final CompletableFuture<Integer> promise = new CompletableFuture<>();
    asyncHttpClient
        .prepareGet("https://msdn.microsoft.com")
        .execute(new AsyncCompletionHandler<Response>(){
            @Override
            public Response onCompleted(Response resp) throws Exception {
                promise.complete(resp.getResponseBody().length());
                return resp;
            }
        });
    return promise;
}

두 번째 접근법은 장황하지만 스레드를 차단합니다.

static CompletableFuture<Integer> AccessTheWebAsync(){
    try(AsyncHttpClient asyncHttpClient = new AsyncHttpClient()){
        Future<Response> f = asyncHttpClient
            .prepareGet("https://msdn.microsoft.com")
            .execute();
        return CompletableFuture.supplyAsync(
            () -> return f.join().getResponseBody().length());
    }
}

Java 바이트 코드 개서를 하는ea-async를 체크하여 비동기/대기 시뮬레이션을 꽤 잘합니다.readme에 따르면 "의 Async-Awit에서 크게 영감을 받았습니다.넷 CLR"

비동기대기당은 통사당입니다.비동기 및 대기 기능의 본질은 상태 머신입니다.컴파일러는 비동기/대기 코드를 스테이트 머신으로 변환합니다.

동시에 실제 프로젝트에서 비동기/대기 기능을 실제로 사용할 수 있도록 하려면 많은 비동기 I/O 라이브러리 기능이 이미 설치되어 있어야 합니다.C#의 경우 대부분의 원래 동기화된 I/O 기능에는 대체 비동기 버전이 있습니다.이러한 비동기 함수가 필요한 이유는 대부분의 경우 자체 비동기/대기 코드가 라이브러리 비동기 방식으로 요약되기 때문입니다.

C#의 비동기 버전라이브러리 함수는 Java의 Asynchronous Channel 개념과 비슷합니다.예를 들어 Asynchronous File Channel.read는 Future를 반환하거나 읽기 작업이 완료된 후 콜백을 실행할 수 있습니다.하지만 꼭 같지는 않아요.모든 C# 비동기 함수는 태스크를 반환합니다(Future와 비슷하지만 Future보다 강력합니다).

Java가 비동기/대기 기능을 지원한다고 가정하면 다음과 같은 코드를 작성합니다.

public static async Future<Byte> readFirstByteAsync(String filePath) {
    Path path = Paths.get(filePath);
    AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);

    ByteBuffer buffer = ByteBuffer.allocate(100_000);
    await channel.read(buffer, 0, buffer, this);
    return buffer.get(0);
}

그러면 컴파일러는 원래의 비동기/대기 코드를 다음과 같이 변환합니다.

public static Future<Byte> readFirstByteAsync(String filePath) {

    CompletableFuture<Byte> result = new CompletableFuture<Byte>();

    AsyncHandler ah = new AsyncHandler(result, filePath);

    ah.completed(null, null);

    return result;
}

AsyncHandler의 실장은 다음과 같습니다.

class AsyncHandler implements CompletionHandler<Integer, ByteBuffer>
{
    CompletableFuture<Byte> future;
    int state;
    String filePath;

    public AsyncHandler(CompletableFuture<Byte> future, String filePath)
    {
        this.future = future;
        this.state = 0;
        this.filePath = filePath;
    }

    @Override
    public void completed(Integer arg0, ByteBuffer arg1) {
        try {
            if (state == 0) {
                state = 1;
                Path path = Paths.get(filePath);
                AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);

                ByteBuffer buffer = ByteBuffer.allocate(100_000);
                channel.read(buffer, 0, buffer, this);
                return;
            } else {
                Byte ret = arg1.get(0);
                future.complete(ret);
            }

        } catch (Exception e) {
            future.completeExceptionally(e);
        }
    }

    @Override
    public void failed(Throwable arg0, ByteBuffer arg1) {
        future.completeExceptionally(arg0);
    }
}

언어 레벨에서 Java에서는 C#async/ait와 동등한 것은 없습니다.파이버 스레드(Fiber cooperative thread) 또는 경량 스레드(lightweight thread)로 알려진 개념이 흥미로운 대안이 될 수 있습니다.파이버를 지원하는 Java 라이브러리를 찾을 수 있습니다.

파이버를 구현하는 Java 라이브러리

기사(Quasar에서)읽고 섬유에 대해 자세히 알아보십시오.스레드가 무엇인지, JVM에서 파이버를 구현하는 방법과 Quasar 관련 코드가 포함되어 있습니다.

앞에서 설명한 바와 같이 직접 동등한 것은 없지만 Java 바이트 코드 수정(비동기/대기형 명령 및 기본 연속 구현)을 통해 매우 가까운 근사치를 생성할 수 있습니다.

JavaFlow 계속 라이브러리 위에 비동기/비동기 구현 프로젝트를 진행 중입니다.https://github.com/vsilaev/java-async-await 를 확인해 주세요.

Maven mojo는 아직 작성되지 않았지만 제공된 Java 에이전트로 예를 실행할 수 있습니다.비동기/대기 코드는 다음과 같습니다.

public class AsyncAwaitNioFileChannelDemo {

public static void main(final String[] argv) throws Exception {

    ...
    final AsyncAwaitNioFileChannelDemo demo = new AsyncAwaitNioFileChannelDemo();
    final CompletionStage<String> result = demo.processFile("./.project");
    System.out.println("Returned to caller " + LocalTime.now());
    ...
}


public @async CompletionStage<String> processFile(final String fileName) throws IOException {
    final Path path = Paths.get(new File(fileName).toURI());
    try (
            final AsyncFileChannel file = new AsyncFileChannel(
                path, Collections.singleton(StandardOpenOption.READ), null
            );              
            final FileLock lock = await(file.lockAll(true))
        ) {

        System.out.println("In process, shared lock: " + lock);
        final ByteBuffer buffer = ByteBuffer.allocateDirect((int)file.size());

        await( file.read(buffer, 0L) );
        System.out.println("In process, bytes read: " + buffer);
        buffer.rewind();

        final String result = processBytes(buffer);

        return asyncResult(result);

    } catch (final IOException ex) {
        ex.printStackTrace(System.out);
        throw ex;
    }
}

@async는 메서드에 비동기 실행 가능 플래그를 붙이는 주석입니다.wait()는 Completetable에서 대기하는 함수입니다.continuations와 return asyncResult(someValue) 호출을 사용하여 관련 Completetable을 완성합니다.미래/계속

C#과 마찬가지로 제어 플로우가 유지되고 예외 처리가 정기적으로 이루어집니다(순차적으로 실행되는 코드와 같은 시도/캐치).

Java 자체에는 동등한 기능이 없지만 Kilim과 같은 유사한 기능을 제공하는 서드파티 라이브러리가 존재합니다.

Java에는 비동기/대기라고 불리는 C# 언어 기능과 직접 동등한 기능이 없지만, 비동기/대기라는 문제에 대한 다른 접근 방식이 있습니다.이것은 프로젝트 Loom이라고 불리며 높은 처리량 동시성을 위한 가상 스레드를 제공합니다.향후 OpenJDK 버전에서 사용할 수 있습니다.

이 접근방식은 비동기/대기 시 발생하는 "색상 함수 문제"도 해결합니다.

골랑(고루틴)에서도 비슷한 특징을 찾을 수 있다.

먼저 비동기/대기란 무엇입니까?이는 단일 스레드 GUI 애플리케이션 또는 효율적인 서버가 단일 스레드에서 여러 개의 "파이버", "동일" 또는 "경량 스레드"를 실행하는 방법입니다.

스레드를 은 Java입니다.ExecutorService.submit ★★★★★★★★★★★★★★★★★」Future.get작업이 완료될 때까지 차단되고 결과가 반환됩니다.한편, 다른 스레드도 작업을 할 수 있습니다.

파이버 등의 이점을 얻으려면 컨테이너(즉 GUI 이벤트루프 또는 서버 HTTP 요청 핸들러) 또는 자체 기입을 통해 지원이 필요합니다.

서블릿 3.0의 서블릿입니다.는 JavaFX를 제공합니다.javafx.concurrent.Task하지만 이것들은 언어의 우아함을 가지고 있지는 않다.일반 콜백을 통해 작동합니다.

async/ait 키워드처럼 Java 네이티브를 사용할 수 있는 것은 없지만 Count Down Latch를 사용하는 것이 좋습니다.다음으로 (적어도 Java7에서는) 이것을 전달함으로써 비동기/대기 상태를 모방할 수 있습니다.이것은 Android 유닛 테스트의 일반적인 관행으로, 비동기 콜(통상은 핸들러에 의해 게시된 실행 가능)을 발신한 후 결과를 대기(카운트다운)해야 합니다.

단, 테스트와는 달리 어플리케이션 내에서 이것을 사용하는 은 권장하지 않습니다.Count Down Latch는 올바른 횟수와 장소에서 카운트다운을 효과적으로 해야 하기 때문에 매우 조잡합니다.

자바 비동기/대기 라이브러리를 만들어 출시했습니다.https://github.com/stofu1234/kamaitachi

이 라이브러리는 컴파일러 확장을 필요로 하지 않으며, Java에서 스택리스 IO 처리를 실현합니다.

    async Task<int> AccessTheWebAsync(){ 
        HttpClient client= new HttpClient();
        var urlContents= await client.GetStringAsync("http://msdn.microsoft.com");
       return urlContents.Length;
    }

    //LikeWebApplicationTester.java
    BlockingQueue<Integer> AccessTheWebAsync() {
       HttpClient client = new HttpClient();
       return awaiter.await(
            () -> client.GetStringAsync("http://msdn.microsoft.com"),
            urlContents -> {
                return urlContents.length();
            });
    }
    public void doget(){
        BlockingQueue<Integer> lengthQueue=AccessTheWebAsync();
        awaiter.awaitVoid(()->lengthQueue.take(),
            length->{
                System.out.println("Length:"+length);
            }
            );
    }

Java에는 비동기/대기 기능이 없습니다.Listenable을 통해 가장 가까운 정보를 얻을 수 있습니다.Guava와 청취자 체인의 미래이지만, 네스트 레벨이 매우 빠르게 증가하기 때문에 여러 비동기 콜을 포함하는 경우에 쓰는 것은 여전히 매우 번거로울 수 있습니다.

JVM 상에서 다른 언어를 사용해도 괜찮으시다면 다행히 Scala에 비동기/비동기 기능이 있습니다.이것은 구문과 의미가 거의 같은 C# 비동기/비동기/비동기 직접 대응입니다.https://github.com/scala/async/

이 기능은 C#에서 상당히 고급 컴파일러 지원이 필요하지만 Scala에서는 Scala의 매우 강력한 매크로 시스템 덕분에 라이브러리로 추가할 수 있으므로 2.10과 같은 이전 버전의 Scala에도 추가할 수 있습니다.또한 Scala는 Java와 클래스 호환성이 있으므로 Scala에서 비동기 코드를 작성한 후 Java에서 호출할 수 있습니다.

Akka Dataflow http://doc.akka.io/docs/akka/2.3-M1/scala/dataflow.html이라는 다른 유사한 프로젝트도 있습니다.이 프로젝트는 다른 표현을 사용하지만 개념적으로는 매우 유사하지만 매크로가 아닌 구분된 연속성을 사용하여 구현됩니다(따라서 2.9와 같은 이전 Scala 버전에서도 작동합니다).

AsynHelper Java 라이브러리에는 이러한 비동기 호출(및 대기)에 대한 유틸리티 클래스/메서드 세트가 포함되어 있습니다.

일련의 메서드 콜 또는 코드 블록을 비동기적으로 실행하는 경우, 아래 스니펫과 같이 유용한 도우미 메서드 AsyncTask.submitTasks가 포함됩니다.

AsyncTask.submitTasks(
    () -> getMethodParam1(arg1, arg2),
    () -> getMethodParam2(arg2, arg3)
    () -> getMethodParam3(arg3, arg4),
    () -> {
             //Some other code to run asynchronously
          }
    );

모든 비동기 코드 실행이 완료될 때까지 기다리는 경우 AsyncTask.submitTasksAndWait 변수를 사용할 수 있습니다.

또한 각 비동기 메서드콜 또는 코드블록에서 반환값을 취득하는 경우에도 AsyncSupplier.submitSuppliers를 사용하여 메서드에 의해 반환된 결과 공급자 배열에서 결과를 얻을 수 있습니다.다음은 샘플 스니펫입니다.

Supplier<Object>[] resultSuppliers = 
   AsyncSupplier.submitSuppliers(
     () -> getMethodParam1(arg1, arg2),
     () -> getMethodParam2(arg3, arg4),
     () -> getMethodParam3(arg5, arg6)
   );

Object a = resultSuppliers[0].get();
Object b = resultSuppliers[1].get();
Object c = resultSuppliers[2].get();

myBigMethod(a,b,c);

각 메서드의 반환 유형이 다를 경우 다음과 같은 스니펫을 사용하십시오.

Supplier<String> aResultSupplier = AsyncSupplier.submitSupplier(() -> getMethodParam1(arg1, arg2));
Supplier<Integer> bResultSupplier = AsyncSupplier.submitSupplier(() -> getMethodParam2(arg3, arg4));
Supplier<Object> cResultSupplier = AsyncSupplier.submitSupplier(() -> getMethodParam3(arg5, arg6));

myBigMethod(aResultSupplier.get(), bResultSupplier.get(), cResultSupplier.get());

비동기 메서드 호출/코드 블록의 결과는 다음 스니펫과 같이 같은 스레드 또는 다른 스레드 내의 다른 코드 포인트에서 얻을 수도 있습니다.

AsyncSupplier.submitSupplierForSingleAccess(() -> getMethodParam1(arg1, arg2), "a");
AsyncSupplier.submitSupplierForSingleAccess(() -> getMethodParam2(arg3, arg4), "b");
AsyncSupplier.submitSupplierForSingleAccess(() -> getMethodParam3(arg5, arg6), "c");


//Following can be in the same thread or a different thread
Optional<String> aResult = AsyncSupplier.waitAndGetFromSupplier(String.class, "a");
Optional<Integer> bResult = AsyncSupplier.waitAndGetFromSupplier(Integer.class, "b");
Optional<Object> cResult = AsyncSupplier.waitAndGetFromSupplier(Object.class, "c");

 myBigMethod(aResult.get(),bResult.get(),cResult.get());

Java에서 비동기/대기 모드와 동일한 효과를 시뮬레이션하는 클린 코드 직후에 테스트 등에서 종료될 때까지 스레드를 차단하는 것을 꺼리지 않는 경우 다음과 같은 코드를 사용할 수 있습니다.

interface Async {
    void run(Runnable handler);
}

static void await(Async async) throws InterruptedException {

    final CountDownLatch countDownLatch = new CountDownLatch(1);
    async.run(new Runnable() {

        @Override
        public void run() {
            countDownLatch.countDown();
        }
    });
    countDownLatch.await(YOUR_TIMEOUT_VALUE_IN_SECONDS, TimeUnit.SECONDS);
}

    await(new Async() {
        @Override
        public void run(final Runnable handler) {
            yourAsyncMethod(new CompletionHandler() {

                @Override
                public void completion() {
                    handler.run();
                }
            });
        }
    });

EA가 개발한 대기 기능(https://github.com/electronicarts/ea-async)이 있습니다.Java 의 샘플 코드를 참조해 주세요.

import static com.ea.async.Async.await;
import static java.util.concurrent.CompletableFuture.completedFuture;

public class Store
{
    public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
    {
        if(!await(bank.decrement(cost))) {
            return completedFuture(false);
        }
        await(inventory.giveItem(itemTypeId));
        return completedFuture(true);
    }
}

이를 위해 라이브러리 JAsync를 개발했습니다.오늘 발매된 지 얼마 안 됐어요.코드 스타일과 디버깅을 포함하여 개발자의 비동기 프로그래밍 경험을 가능한 한 일반적인 동기 프로그래밍에 가깝게 만듭니다.여기 예가 있습니다.

@RestController
@RequestMapping("/employees")
public class MyRestController {
    @Inject
    private EmployeeRepository employeeRepository;
    @Inject
    private SalaryRepository salaryRepository;

    // The standard JAsync async method must be annotated with the Async annotation, and return a Promise object.
    @Async()
    private Promise<Double> _getEmployeeTotalSalaryByDepartment(String department) {
        double money = 0.0;
        // A Mono object can be transformed to the Promise object. So we get a Mono object first.
        Mono<List<Employee>> empsMono = employeeRepository.findEmployeeByDepartment(department);
        // Transformed the Mono object to the Promise object.
        Promise<List<Employee>> empsPromise = JAsync.from(empsMono);
        // Use await just like es and c# to get the value of the Promise without blocking the current thread.
        for (Employee employee : empsPromise.await()) {
            // The method findSalaryByEmployee also return a Mono object. We transform it to the Promise just like above. And then await to get the result.
            Salary salary = JAsync.from(salaryRepository.findSalaryByEmployee(employee.id)).await();
            money += salary.total;
        }
        // The async method must return a Promise object, so we use just method to wrap the result to a Promise.
        return JAsync.just(money);
    }

    // This is a normal webflux method.
    @GetMapping("/{department}/salary")
    public Mono<Double> getEmployeeTotalSalaryByDepartment(@PathVariable String department) { 
        // Use unwrap method to transform the Promise object back to the Mono object.
        return _getEmployeeTotalSalaryByDepartment(department).unwrap(Mono.class);
    }
}

디버깅 모드에서는 동기 코드와 마찬가지로 모든 변수를 볼 수 있습니다.

여기에 이미지 설명 입력

이 프로젝트의 또 다른 장점은 현재도 몇 안 되는 프로젝트 중 하나라는 것입니다.발매된 지 얼마 안 된 곡이기 때문에 많은 가능성을 가지고 있습니다.

언급URL : https://stackoverflow.com/questions/16539245/java-equivalent-of-c-sharp-async-await

반응형