멀티 프로세싱으로 연산 프로그램 성능 올리기
부동산 지수를 계산하기 위해 많은 양의 데이터를 처리하는 중에 메모리 문제와 연산 속도가 느린 문제가 발생했지만, 병렬 처리를 통해 프로세스 간 연산을 나눠서 진행하여 성능을 개선했다. 결과적으로 파일로 저장하면서 메모리 문제도 해결되었고, 멀티 프로세싱을 통해 CPU 자원을 효율적으로 사용하여 빠르게 연산이 가능해졌다.
1개의 댓글
0개의 질문
깐지닉
백엔드 개발자 정진우입니다. (https://github.com/comolove)
부동산 지수를 계산하기 위해 많은 양의 데이터를 처리하는 중에 메모리 문제와 연산 속도가 느린 문제가 발생했지만, 병렬 처리를 통해 프로세스 간 연산을 나눠서 진행하여 성능을 개선했다. 결과적으로 파일로 저장하면서 메모리 문제도 해결되었고, 멀티 프로세싱을 통해 CPU 자원을 효율적으로 사용하여 빠르게 연산이 가능해졌다.
1개의 댓글
0개의 질문
FastAPI 프로젝트에서 기존 방식의 커스텀 에러 처리를 개선하기 위해 Not Found 에러를 추가하고, 이를 관리하는 패키지와 핸들러를 만들어 등록하는 방법을 소개하였다. 요청 시 발생한 404 코드와 메시지를 반환하는 핸들러 등록은 앱의 구조 변경과 유지보수에 도움이 될 것으로 기대된다.
0개의 댓글
0개의 질문
FastAPI 프로젝트의 구조가 변경되어 SQLAlchemy session 사용 방식이 바뀌었고, service 레이어를 service와 repository 레이어로 분리하며 response schema와 dto도 분리되었습니다. 또한 BaseRepository를 통해 CRUD 기능을 제공하고, 세션 사용 방법과 트랜잭션 처리 등에 대한 내용도 변경되었습니다.
0개의 댓글
0개의 질문
Nginx의 설정 파일인 nginx.conf에는 include 지시자를 사용하여 다른 파일을 포함할 수 있으며, 이로 인해 상속 관계 문제가 발생할 수 있습니다. default.conf를 include하는 경우, 중복 설정으로 인한 충돌을 방지하기 위해 주의가 필요합니다.
0개의 댓글
0개의 질문
RabbitMQ Producer 설정 정보를 알아보았습니다. RabbitMQ에서는 네 가지 프로토콜을 지원하며, Acknowledgement mechanism을 통해 데이터의 안전성을 보장합니다. 또한 Channel과 Exchange를 통해 메시지를 전달하고 Queue에 저장하는 방법에 대해서도 알아보았습니다.
0개의 댓글
0개의 질문
코틀린에서는 Structual Equality(내용 동등성)과 Referential Equality(참조 동일성)이 존재하며, 자바와의 차이를 분석할 때 equals와 == 연산자의 역할을 비교해야 한다. 객체의 내용을 비교하는 equals 메서드는 Java에서도 주소값 뿐만 아니라 내용도 확인하며, Kotlin에서는 이에 대응하기 위해 == 연산자를 사용한다.
1개의 댓글
0개의 질문
FastAPI 앱을 Gunicorn과 Uvicorn으로 실행하는 경우, Gunicorn은 WSGI standard를 사용하기 때문에 fastapi와는 잘 맞지 않지만, Uvicorn은 ASGI standard를 사용하여 적합하나 단일 프로세스 한계가 있다. 멀티 코어 환경에서는 Gunicorn으로 Uvicorn 워커를 여러개 사용하는 것이 이점이 있으며, 단일 프로세스로 여러 컨테이너를 띄우는 것이 scale-out에 유리하다.
0개의 댓글
0개의 질문
Scroll Restoration은 페이지 이동 후 이전 스크롤 위치를 유지하는 기능으로, Next.js 13.4.13 버전에서 문제가 해결되었으며 Docker 파일 수정을 통해 문제를 해결할 수 있다. Scroll Restoration이 잘 동작하여 프로덕션 배포에도 성공적으로 적용되었다.
1개의 댓글
0개의 질문
스프링 데이터 JPA에서는 사용자 정의 리포지토리를 구현하기 위해 추가적인 인터페이스와 구현체 클래스를 생성하여 사용할 수 있습니다. 또한, Auditing 엔티티를 생성하고 변경 시간과 사람을 추적하기 위해 공통 필드들을 정의하여 상속하는 방법이 있습니다. 이러한 기능들은 스프링 데이터 JPA로는 부족할 때 유용하게 사용될 수 있습니다.
0개의 댓글
0개의 질문
SWEA - 햄버거 다이어트(5215)에서는 조합을 사용하여 제한 칼로리 내에서 최대 맛에 대한 점수를 구하는 문제를 해결하는 코드입니다. 주어진 재료의 수와 제한 칼로리를 변수로 받아오고, 각 재료의 맛에 대한 점수와 칼로리를 리스트에 할당합니다. 그 후, 조합을 이용하여 가능한 모든 경우의 수를 계산하고 최대 점수를 구합니다.
1개의 댓글
0개의 질문
memo memo 자동생성 AI기반의 글쓰기 도우미입니다. 이전 텍스트를 기반으로 문맥을 파악하여 완전한 문장을 작성합니다. 어떤 내용에 대해 도움이 필요하신가요?
0개의 댓글
0개의 질문
NFT(Non-fungible token)는 교환, 복제, 삭제가 불가능하며 고유성을 갖는 블록체인 기반 토큰이다. NFT를 발행하기 위해서는 Smart Contract를 작성하고 배포해야 하며, 이더리움 기반의 ERC-721 표준을 준수해야 한다.
0개의 댓글
0개의 질문
Inforum은 생성형 AI를 활용하여 텍스트 자동 생성, 태그 및 요약 기능을 제공합니다. 또한 메모를 통합하여 시리즈로 출간하고, 기술 포스트와 연동된 질문/답변 기능도 제공됩니다. 등급제와 Post History를 통해 동기부여도 가능합니다.
0개의 댓글
0개의 질문
기술블로그를 쓸 생각을 했지만 실천하지 못했다면, Inforum이라는 웹서비스를 소개합니다. Inforum은 기술 질문과 답변 커뮤니티로, 간편하고 편리하게 사용할 수 있습니다. 현재 회원가입 후 글 작성과 설문조사 참여 시 네이버페이 3000원 지급 이벤트도 진행 중입니다.
1개의 댓글
0개의 질문
기존에는 execCommand 라는 함수가 사용되었으나 deprecate되면서 Clipboard API를 권장하게 되었다. navigator.clipboard.writeText() 위 메서드의 parameter로 복사할 값을 넣으면 된다. 만약 복사에 성공하면 toast를 띄우는 등의 동작을 하고 싶다면 then으로 연결하면 된다. navigator.clipboard.writeText(\"\").then(() => 동작) 주의! localhost 가 아닌 http 환경에서는 동작하지 않는다. (에러가 발생한다)
0개의 댓글
0개의 질문
테스트 도중 JSON 데이터를 DB에 저장하는 로직이 있어, Controller 에서 JSON 데이터를 String 으로 받고, DB에 넣을 때 JSON으로 파싱해주는 로직이 있었다. 문제 상황 String answerSaveForm =\n \"{\" +\n \"\\\"text\\\": \\\"{\\\"content\\\": \\\"good\\\ 컨트롤러에서 파싱하여 text 필드에 \"{\"content\":\"good\ DB 에서 JSONB 로 파싱할 때 에러가 발생 DB 에서 다시 JSONB 데이터로 파싱할 때는 \"{\\\"content\\\":\\\"good\\\ 해결 String answerSaveForm =\n \"{\" +\n \"\\\"text\\\": \\\"{\\\\\\\"content\\\\\\\": \\\\\\\"good\\\\\\\
2개의 댓글
0개의 질문
(스크린샷은 향후 추가 예정) (틀린 점, 궁금한 점은 적극적으로 공유해주셔도 좋습니다!) 개발자분들이 늘 고민을 많이 하시는 부분이 개발 환경이라고 저는 종종 생각합니다. 그렇기에 개발 환경은 개발자들에게 항상 중요한 고민거리입니다. 저 역시 최대한 다양한 환경을 테스트해보고 내가 사용하기 좋은 환경일지 고민해보죠. 이 과정에서 새로이 쓰게 된 개발환경이 바로 Neovim과 NvChad 입니다. Vim? Neovim? Vim은 우리가 모두 들어봤을 거 같은데요, 대부분의 Linux/Unix 환경에 탑재되어 있는 친구가 바로 Vim입니다. 잘 쓰는 분들은 Vim으로 날라다니시지만, 저는 그러지 못해서, Neovim을 알기 전까지는 제대로 써보지 못했습니다. Neovim은 여러분이 잘 아시는 그 Vim에 확장성, 좀 더 향상된 UI 등을 접목한 Vim의 후예같은 친구입니다. Vim도 plugin 등을 적용할 수 있지만 Neovim은 더 사용하기 편안하도록 VSCode와 유사한 UI, Launguage Server Support 등을 지원합니다. 기존의 내장 기능만을 사용하는 Vim과는 어느정도 차이가 있죠. 왜 Vim? Vim을 선택한 건 갑작스러운 변덕이라기보다는, 하나의 불행에서 시작되었습니다. (제게는) VSCode의 필수 extension인 Remote-SSH가 먹통이 되었거든요. 물론 그 버그는 금방 해결되었습니다만... 하루를 생으로 날려보낼 수는 없던 제 입장에서는 이런 상황이 생길 때를 대비한 backup이 필요했고 그 과정에서 가볍지만 원하는 기능을 모두 제공하는 Vim을 사용해봤습니다. 다만 Vim만을 사용하지는 않았죠. NvChad? 앞에서 언급드렸다시피 Neovim은 확장성, 향상된 UI 등을 제공합니다. 하지만 Vim 초심자에게 있어 Neovim의 설정을 바로 하기에는 좀 (많이) 어렵습니다. 그래서, 초심자들을 위한 plugin과 설정의 집합?과 같은 녀석들이 등장했죠. NvChad, LunarVim 과 같은 친구들이 그 친구들이죠. (얼마나 꾸준히 작성할지는 잘 모르겠지만) 밑밥을 열심히 깔아 두었으니 이제부터 조금씩 설정하면서 삽질한 이야기들을 해보려고 합니다. 두서없는 글 봐주셔서 감사하고 만약 계속 따라오실 예정이시라면 앞으로 잘 부탁드립니다. Reference. https://github.com/NvChad/NvChad https://github.com/neovim/neovim
1개의 댓글
0개의 질문
1. Soft Delete Soft Delete란 soft delete는 database 의 테이블에서 물리적으로 데이터를 삭제하는 대신 마킹을 통해서 delete 를 구현하는 방식이다. soft delete를 구현하는 가장 보편화된 방식은 삭제여부를 나타내는 field 를 추가하는 방식이다. 다음은 deleted 란 field 를 통해 삭제 여부를 관리하는 방식의 예시이다. Soft Delete 수행법 해당 테이블에서 다음과 같은 SQL command를 통해 delete 작업을 수행할 수 있다. update from post set deleted=1 where id=1\n soft delete 방식을 도입하면 테이블 조회 방식도 바뀌게 된다. select * from post where deleted=0\n 2. Soft Delete 구현 post entity @Entity\n@Getter\n@NoArgsConstructor(access = AccessLevel.PROTECTED)\n@AllArgsConstructor(access = AccessLevel.PROTECTED)\n@Builder\npublic class Post {\n\n @Id @GeneratedValue(strategy = GenerationType.IDENTITY)\n private Long id;\n\n @NotNull\n private String title;\n\n @NotNull\n private String content;\n\n @NotNull\n private String writer;\n\n private boolean deleted = Boolean.FALSE;\n}\n\n 위 코드를 보면 post 엔티티에 default 값을 false 로 둔 deleted 변수를 추가하여 soft delete를 구현한 것을 확인할 수 있다. 이런 방식으로 구현하면 삭제할 때마다 update 쿼리를 날려야 하고 조회 할때마다 where 절을 통해 deleted=false 인 데이터만 조회하도록 쿼리를 작성해야 한다. 다음과 같은 JPA repsitory 의 delete command를 오버라이드하여 해당 작업을 간편화 할 수 있다. @Entity\n@Getter\n@NoArgsConstructor(access = AccessLevel.PROTECTED)\n@AllArgsConstructor(access = AccessLevel.PROTECTED)\n@Builder\n@SQLDelete(sql = \"UPDATE post SET deleted = true WHERE id=?\") - (1)\n@Where(clause = \"deleted=false\") - (2)\npublic class Post {\n\n @Id @GeneratedValue(strategy = GenerationType.IDENTITY)\n private Long id;\n\n @NotNull\n private String title;\n\n @NotNull\n private String content;\n\n @NotNull\n private String writer;\n\n private boolean deleted = Boolean.FALSE;\n\n public void update(String title, String content) {\n this.title = title;\n this. content = content;\n }\n}\n\n (1) @SQLDelete annotation을 통해 delete command를 deleted=true 로 update 하는 SQL command로 바꾼다. (2) @Where annotation을 통해 deleted=false 인 데이터만 조회하도록 한다. Repository public interface PostRepository extends JpaRepository<Post, Long> {\n}\n PostRepository 에는 특별한 변경점이 없다. Service @RequiredArgsConstructor\n@Service\npublic class PostService {\n\n private final PostRepository postRepository;\n\n public Long create(PostRequest postRequest) {\n Post post = postRequest.toEntity();\n return postRepository.save(post).getId();\n }\n\n public PostResponse getPost(long postId) {\n Post findPost = findPostById(postId);\n return PostResponse.builder()\n .post(findPost)\n .build();\n }\n\n public PostsResponse getPosts() {\n List<Post> posts = postRepository.findAll();\n return PostsResponse.builder()\n .postResponses(posts.stream()\n .map(post -> PostResponse.builder()\n .post(post)\n .build())\n .collect(Collectors.toList()))\n .build();\n }\n\n public Long update(Long postId,PostUpdateRequest postUpdateRequest) {\n Post findPost = findPostById(postId);\n findPost.update(postUpdateRequest.getTitle(), postUpdateRequest.getContent());\n return postRepository.save(findPost).getId();\n }\n\n public void delete(long postId) {\n postRepository.deleteById(postId);\n }\n\n private Post findPostById(long postId) {\n return postRepository.findById(postId).orElseThrow(() -> new NotFoundException(ErrorCode.ENTITY_NOT_FOUND.getMessage()));\n }\n}\n PostService 에도 특별한 변경사항 없이 원래 쓰던 deleteById 를 사용하면 update 쿼리로 변환되어 soft delete가 수행된다. 조회 메소드 또한 조회시 where 절에 deleted=false 가 추가되어 쿼리를 날리게 된다. 출처 How to Implement a Soft Delete with Spring JPA
3개의 댓글
0개의 질문
Java String Pool Java에서 문자열을 표현하는 String은 불변객체다. String name = \"jeongyun\";\nname += \"eo\";\nSystem.out.println(name); // jeongyuneo 위 코드에서 name에 문자열을 더한다고 해서 문자열의 값이 바뀌는 것이 아니라, 새로운 객체를 만들어 그 참조값을 참조하게 된다. 만약 같은 값을 갖는 문자열을 여러 번 선언한다면, Heap 영역에 매번 새로운 객체를 생성하게 될 것이다. 이는 메모리 낭비로 이어진다. 따라서 Java는 문자열 객체를 캐싱(caching)한다. 💡 캐싱(caching) 데이터를 미리 복사해 임시 저장해놓는 것 데이터 접근 시간을 줄일 수 있음 String Pool Java의 Heap 영역에는 String Pool이 존재하고, String Pool이 String 객체들을 관리한다. String Pool은 HashTable 구조를 갖고 있다. 문자열 리터럴을 사용해 문자열 객체를 생성하면 String Pool에 같은 값을 가지는 String 객체가 있는지 검사하고 있다면 그 객체의 참조값을, 없다면 새로운 String 객체를 생성해 그 객체의 참조값을 반환한다. 이러한 과정을 ‘intern’이라고 한다. String 객체를 위 코드처럼 리터럴로 생성 시 내부적으로 intern() 이라는 메소드를 실행해 수행한다. 따라서 같은 문자열은 myPet과 hisPet 두 객체의 참조값을 비교하는 동일성 비교(==)에도 true 가 반환됨을 확인할 수 있다. 반대로 new String(”문자열”) 을 이용해 생성된 객체들은 String Pool이 아닌 Heap 영역에 생성된다. 각각의 객체들은 서로 다른 참조값을 갖고 있기 때문에 이런 방식으로 생성된 myPet과 hisPet 두 객체의 참조값을 비교하는 동일성 비교(==)에서 false 가 반환됨을 확인할 수 있다. Java 6까지 String Pool은 Heap 영역 안에서도 Perm 영역에 있었다. 이때문에 String Pool에 문자열 객체가 많이 생성되거나 다른 이유로 이 영역이 가득 차게되면, 런타임 환경에서 메모리를 동적으로 늘리지 못해 OutOfMemoryException 발생했다. Java 7에서는 다른 일반 객체들과 마찬가지로 Perm 영역이 아닌 Heap 영역에 String Pool을 생성해서 OutOfMemoryException이 발생했을 때의 위험성을 줄였다. Java 8부터는 고정 크기로 많은 문제를 일으켰던 Perm 영역은 Metaspace로 이름을 변경하고 동적크기 메모리 구성으로 변경되었다.
1개의 댓글
1개의 질문
Springdoc를 배포 환경에서 안 보이게 하기 위해 yml 파일에 설정을 추가하여 domain/swagger-ui/index.html로의 접근을 비활성화할 수 있다.
0개의 댓글
0개의 질문