我目前面临一个问题,我给一个线程一个集合的引用,我希望能够用模拟的数据库调用替换该集合.到目前为止,我已经完成了

import logging
import threading
import time
from typing import Callable

from loguru import logger


class MonitorProduct:

    def __init__(self, term: str, is_alive: Callable[[str], bool]) -> None:
        self.is_alive = is_alive
        self.term = term

    def do_request(self) -> None:
        time.sleep(.1)
        while True:
            logger.info(f'Checking {self.term}')
            if not self.is_alive(self.term):
                logger.info(f'Deleting term from monitoring: "{self.term}"')
                return

            time.sleep(5)


# mocked database
def database_terms() -> set[str]:
    return {
        'hello world',
        'python 3',
        'world',
        'wth',
    }


def database_terms_2() -> set[str]:
    return {
        'what am I doing wrong',
    }


def main() -> None:
    terms: set[str] = set()

    while True:
        db_terms = database_terms()
        diff = db_terms - terms
        terms.symmetric_difference_update(db_terms)

        for url in diff:
            logger.info(f'Starting URL: {url}')
            threading.Thread(
                target=MonitorProduct(url, terms.__contains__).do_request
            ).start()

        time.sleep(2)

        # ----------------------------------------------- #

        db_terms = database_terms_2() 
        diff = db_terms - terms
        terms.symmetric_difference_update(db_terms) # <--- terms should only now contain `what am I doing wrong`

        # Start the new URLS
        for url in diff:
            logger.info(f'Starting URL 2: {url}')
            threading.Thread(
                target=MonitorProduct(url, terms.__contains__).do_request
            ).start()

        time.sleep(10)


if __name__ == '__main__':
    main()

我现在遇到的问题是,当我们执行第一个db调用时,它应该 for each 术语启动线程:

{
  'hello world',
  'python 3',
  'world',
  'wth',
}

正如你们所见,我们还 for each 线程发送了terms.__contains__.

当我们第二次调用db时,该集合应该替换terms

{
  'what am I doing wrong',
}

由于以下原因,最终应退出四个运行线程:

def do_request(self) -> None:
        time.sleep(.1)
        while True:
            logger.info(f'Checking {self.term}')
            if not self.is_alive(self.term):
                logger.info(f'Deleting term from monitoring: "{self.term}"')
                return

            time.sleep(5)

然而,问题是,我们不能以行动取代条款

术语=…因为我们正在创建一个新的集合,然后将该集合绑定到变量术语,而线程仍然有一个对旧集合的引用.

我的问题是,如何在不绑定新集合的情况下更新到最新集合来替换旧术语?

推荐答案

你就快到了.但是

diff = db_terms - terms
terms ^= diff  # symmetric_difference_update()

这还不够,因为这只是添加了新的值,所以它与

terms |= diff  # update()

甚至

terms |= db_terms  # update()

(对于读者来说,其中一个选项应该比对称差分更清楚,因为您没有使用对称差分删除任何内容.)

要删除旧值,您需要执行also

terms &= db_terms  # intersection_update()

你说你关心具有中间值的比赛条件.如果您想从多个线程修改集合,应该在其周围使用互斥锁(threading.RLock).但是,如果您只从一个线程进行修改,并在另一个线程中比较__contains__,那么只要执行的每个步骤都保持集合处于一致状态,就可以避免CPython中的锁定.

Python相关问答推荐

code _tkinter. Tcl错误:窗口路径名称错误.!按钮4"

如何使用Tkinter创建两个高度相同的框架(顶部和底部)?

Locust请求中的Python和参数

使用LineConnection动画1D数据

Polars比较了两个预设-有没有方法在第一次不匹配时立即失败

try 与gemini-pro进行多轮聊天时出错

点到面的Y距离

如何检测背景有噪的图像中的正方形

如何使用matplotlib在Python中使用规范化数据和原始t测试值创建组合热图?

使用miniconda创建环境的问题

使用Python更新字典中的值

为一个组的每个子组绘制,

如何使regex代码只适用于空的目标单元格

dask无groupby(ddf. agg([min,max])?''''

在单次扫描中创建列表

ModuleNotFoundError:没有模块名为x时try 运行我的代码''

如何在Gekko中使用分层条件约束

BeautifulSoup-Screper有时运行得很好,很健壮--但有时它失败了::可能这里需要一些更多的异常处理?

numpy数组和数组标量之间的不同行为

删除Dataframe中的第一个空白行并重新索引列