>

데이터베이스를 반복하면서 모든 Company 를 업데이트하고 있습니다.  개체.

for company in Company.objects.filter(updated=False):
    driver.get(company.company_url)
    company.adress = driver.find_element_by_id("address").text
    company.visited = True    
    company.save()

내 문제는 너무 오래 걸리므로 동일한 코드의 다른 인스턴스를 실행하고 싶지만 실제 DB 읽기가 발생할 때 궁금합니다. 만약 company.visited   True 로 변경  이 루프가 실행되는 동안 여전히이 루프를 방문합니까? visited 에 대한 두 번째 검사를 추가하면 어떻게됩니까 ? 첫 번째 인스턴스가 두 번째 인스턴스의 작업을 인식하지 않으면 두 번째 루프를 시작하고 싶지 않습니다.

for company in Company.objects.filter(updated=False):
    if company.visited:
        continue
    driver.get(company.company_url)
    company.adress = driver.find_element_by_id("address").text
    company.visited = True    
    company.save()


  • 답변 # 1

    Company.objects.filter(updated=False)  일반적인 SQL 쿼리로 번역합니다 :

    SELECT * FROM appName_company WHERE updated is false
    
    
    이 SQL 쿼리는 Company 를 통해 반복을 시작할 때 실행됩니다.  사물. 한 번만 실행됩니다. 두 번째 서버는 첫 번째 서버의 작업을 인식하지 못합니다. 두 서버 모두 동일한 Company 를 거치기 때문입니다.  개체.

    원자 트랜잭션과 select_for_update() 를 사용하여 경쟁 조건을 피하기 위해 행을 잠그십시오. :

    from django.db import transaction
    for company in Company.objects.filter(updated=False):
        with transaction.atomic():
            Company.objects.select_for_update().get(id=company.id)
            if company.visited:
                continue
            driver.get(company.company_url)
            company.adress = driver.find_element_by_id("address").text
            company.visited = True    
            company.save()
    
    

    여러 서버에서이 코드를 실행할 수 있습니다. 각 Company  한 번만 처리됩니다.

    이 코드를 정기적으로 실행해야하는 경우 Celery를 사용하는 것이 좋습니다. 각 회사별로 작업을 전달하고 여러 작업자가 동시에 작업을 수행하도록합니다.

    from celery import shared_task
    @shared_task
    def dispatch_tasks():
        for company in Company.objects.filter(updated=False):
            process_company.delay(company.id)
    @shared_task
    @transaction.atomic
    def process_company(company_id):
        company = Company.objects.select_for_update().get(id=company_id)
        if company.visited:
            continue
        driver.get(company.company_url)
        company.adress = driver.find_element_by_id("address").text
        company.visited = True    
        company.save()
    
    
    <시간>

    수정 : 아, 질문에 sqlite 태그를 달았습니다. SQLite는 동시성이 좋지 않기 때문에 PostgreSQL로 전환하는 것이 좋습니다. 제 답변은 SQlite와 함께 작동하지만 잠금으로 인해 데이터베이스 속도가 느려질 수 있습니다.

관련 자료

  • 이전 xmlhttprequest - Laravel Guzzle 구문 분석 오류 양식 JSON 형식
  • 다음 views-viewhtmltwig 파일에서 컨텐츠 유형을 얻는 방법 | 드루팔 8