コード例 #1
0
def patch_frame_config(MONGO_CONNECT_URL: str = None,

                       RABBITMQ_USER: str = None,
                       RABBITMQ_PASS: str = None,
                       RABBITMQ_HOST: str = None,
                       RABBITMQ_PORT: int = None,
                       RABBITMQ_VIRTUAL_HOST: str = None,

                       REDIS_HOST: str = None,
                       REDIS_PASSWORD: str = None,
                       REDIS_PORT: int = None,
                       REDIS_DB: int = None,

                       NSQD_TCP_ADDRESSES: list = None,
                       NSQD_HTTP_CLIENT_HOST: str = None,
                       NSQD_HTTP_CLIENT_PORT: int = None,
                       KAFKA_BOOTSTRAP_SERVERS: list = None,

                       SQLACHEMY_ENGINE_URL='sqlite:////sqlachemy_queues/queues.db'

                       ):
    """
    对框架的配置使用猴子补丁的方式进行更改。利用了模块天然是单利的特性。格式参考frame_config.py
    :return:
    """
    kw = copy.copy(locals())
    for var_name, var_value in kw.items():
        if var_value is not None:
            setattr(frame_config, var_name, var_value)
    nb_print('使用patch_frame_config 函数设置框架配置了。')
    show_frame_config()
コード例 #2
0
def auto_creat_config_file_to_project_root_path():
    """
    在没有使用pycahrm运行代码时候,如果实在cmd 或者 linux 运行, python xx.py,
    请在临时会话窗口设置linux export PYTHONPATH=你的项目根目录 ,winwdos set PYTHONPATH=你的项目根目录
    :return:
    """
    # print(Path(sys.path[1]).as_posix())
    # print((Path(__file__).parent.parent).absolute().as_posix())
    # if Path(sys.path[1]).as_posix() in Path(__file__).parent.parent.absolute().as_posix():
    #     nb_print('不希望在本项目里面创建')
    #     return
    if '/lib/python' in sys.path[1] or r'\lib\python' in sys.path[
            1] or '.zip' in sys.path[1]:
        raise EnvironmentError(
            f'''如果是cmd 或者shell启动而不是pycharm 这种ide启动脚本,请先在会话窗口设置临时PYTHONPATH为你的项目路径,
                               windwos 使用 set PYTHONNPATH=你的当前python项目根目录,
                               linux 使用 export PYTHONPATH=你的当前你python项目根目录,
                               PYTHONPATH 作用是python的基本常识,请百度一下。
                               需要在会话窗口命令行设置临时的环境变量,而不是修改linux配置文件的方式设置永久环境变量,每个python项目的PYTHONPATH都要不一样,不要在配置文件写死'''
        )
        return  # 当没设置pythonpath时候,也不要在 /lib/python36.zip这样的地方创建配置文件。

    file_name = Path(sys.path[1]) / Path('distributed_frame_config.py')
    copyfile(
        Path(__file__).absolute().parent / Path('frame_config.py'), file_name)
    nb_print(
        f'在  {Path(sys.path[1])} 目录下自动生成了一个文件, 请查看或修改 \n "{file_name}:1" 文件')
コード例 #3
0
def use_config_form_distributed_frame_config_module():
    """
    自动读取配置。会优先读取启动脚本的目录的distributed_frame_config.py文件。没有则读取项目根目录下的distributed_frame_config.py
    :return:
    """
    current_script_path = sys.path[0].replace('\\', '/')
    project_root_path = sys.path[1].replace('\\', '/')
    inspect_msg = f"""
    分布式函数调度框架会自动导入distributed_frame_config模块
    当第一次运行脚本时候,函数调度框架会在你的python当前项目的根目录下 {project_root_path} 下,创建一个名为 distributed_frame_config.py 的文件。
    自动读取配置,会优先读取启动脚本的所在目录 {current_script_path} 的distributed_frame_config.py文件,
    如果没有 {current_script_path}/distributed_frame_config.py 文件,则读取项目根目录 {project_root_path} 下的distributed_frame_config.py做配置。
    在 "{project_root_path}/distributed_frame_config.py:1" 文件中,需要按需重新设置要使用到的中间件的键和值,例如没有使用rabbitmq而是使用redis做中间件,则不需要配置rabbitmq。
    """
    # sys.stdout.write(f'\033[0;33m{time.strftime("%H:%M:%S")}\033[0m  "{__file__}:{sys._getframe().f_lineno}"   \033[0;30;43m{inspect_msg}\033[0m\n')
    # noinspection PyProtectedMember
    sys.stdout.write(
        f'\033[0;93m{time.strftime("%H:%M:%S")}\033[0m  "{__file__}:{sys._getframe().f_lineno}"   \033[0;93;100m{inspect_msg}\033[0m\n')

    try:
        # noinspection PyUnresolvedReferences
        # import distributed_frame_config
        m = importlib.import_module('distributed_frame_config')
        # nb_print(m.__dict__)
        nb_print(f'分布式函数调度框架 读取到\n "{m.__file__}:1" 文件里面的变量作为配置了\n')
        for var_namex, var_valuex in m.__dict__.items():
            if var_namex.isupper():
                setattr(frame_config, var_namex, var_valuex)
    except ModuleNotFoundError:
        nb_print(
            f'''分布式函数调度框架检测到 你的项目根目录 {project_root_path} 和当前文件夹 {current_script_path}  下没有 distributed_frame_config.py 文件,\n\n''')
        auto_creat_config_file_to_project_root_path()


    show_frame_config()
コード例 #4
0
 def join_all_consumer_shedual_task_thread(cls):
     nb_print((cls.schedulal_thread_to_be_join,
               len(cls.schedulal_thread_to_be_join), '模式:',
               cls.global_concurrent_mode))
     if cls.schedual_task_always_use_thread:
         for t in cls.schedulal_thread_to_be_join:
             nb_print(t)
             t.join()
     else:
         if cls.global_concurrent_mode == 1:
             for t in cls.schedulal_thread_to_be_join:
                 nb_print(t)
                 t.join()
         elif cls.global_concurrent_mode == 2:
             # cls.logger.info()
             nb_print(cls.schedulal_thread_to_be_join)
             gevent.joinall(
                 cls.schedulal_thread_to_be_join,
                 raise_error=True,
             )
         elif cls.global_concurrent_mode == 3:
             for g in cls.schedulal_thread_to_be_join:
                 # eventlet.greenthread.GreenThread.
                 nb_print(g)
                 g.wait()
コード例 #5
0
def wait_for_possible_has_finish_all_tasks(
    queue_name: str,
    minutes: int,
    send_stop_to_broker=0,
    broker_kind: int = 0,
):
    """
      由于是异步消费,和存在队列一边被消费,一边在推送,或者还有结尾少量任务还在确认消费者实际还没彻底运行完成。  但有时候需要判断 所有任务,务是否完成,提供一个不精确的判断,要搞清楚原因和场景后再慎用。
    :param queue_name: 队列名字
    :param minutes: 连续多少分钟没任务就判断为消费已完成
    :param send_stop_to_broker :发送停止标志到中间件,这回导致消费退出循环调度。
    :param broker_kind: 中间件种类
    :return:
    """
    if minutes <= 1:
        raise ValueError('疑似完成任务,判断时间最少需要设置为2分钟内,最好是是10分钟')
    pb = get_publisher(queue_name, broker_kind=broker_kind)
    no_task_time = 0
    while 1:
        # noinspection PyBroadException
        try:
            message_count = pb.get_message_count()
        except Exception as e:
            nb_print(e)
            message_count = -1
        if message_count == 0:
            no_task_time += 30
        else:
            no_task_time = 0
        time.sleep(30)
        if no_task_time > minutes * 60:
            break
    if send_stop_to_broker:
        pb.publish({'stop': 1})
    pb.close()
コード例 #6
0
 def show_all_consumer_info(cls):
     nb_print(
         f'当前解释器内,所有消费者的信息是:\n  {json.dumps(cls.consumers_queue__info_map, indent=4, ensure_ascii=False)}'
     )
     for _, consumer_info in cls.consumers_queue__info_map.items():
         sys.stdout.write(
             f'{time.strftime("%H:%M:%S")} "{consumer_info["where_to_instantiate"]}"  \033[0;30;44m{consumer_info["queue_name"]} 的消费者\033[0m\n'
         )
コード例 #7
0
def auto_creat_config_file_to_project_root_path():
    # print(Path(sys.path[1]).as_posix())
    # print((Path(__file__).parent.parent).absolute().as_posix())
    if Path(sys.path[1]).as_posix() in Path(
            __file__).parent.parent.absolute().as_posix():
        nb_print('不希望在本项目里面创建')
        return
    with (Path(sys.path[1]) / Path('distributed_frame_config.py')).open(
            mode='w', encoding='utf8') as f:
        f.write(config_file_content)
コード例 #8
0
def auto_creat_config_file_to_project_root_path():
    # print(Path(sys.path[1]).as_posix())
    # print((Path(__file__).parent.parent).absolute().as_posix())
    if Path(sys.path[1]).as_posix() in Path(
            __file__).parent.parent.absolute().as_posix():
        nb_print('不希望在本项目里面创建')
        return
    if '/lib/python' in sys.path[1] or r'\lib\python' in sys.path[
            1] or '.zip' in sys.path[1]:
        return  # 当没设置pythonpath时候,也不要在 /lib/python36.zip这样的地方创建配置文件。
    with (Path(sys.path[1]) / Path('distributed_frame_config.py')).open(
            mode='w', encoding='utf8') as f:
        f.write(config_file_content)
コード例 #9
0
def auto_creat_config_file_to_project_root_path():
    # print(Path(sys.path[1]).as_posix())
    # print((Path(__file__).parent.parent).absolute().as_posix())
    # if Path(sys.path[1]).as_posix() in Path(__file__).parent.parent.absolute().as_posix():
    #     nb_print('不希望在本项目里面创建')
    #     return
    if '/lib/python' in sys.path[1] or r'\lib\python' in sys.path[1] or '.zip' in sys.path[1]:
        return  # 当没设置pythonpath时候,也不要在 /lib/python36.zip这样的地方创建配置文件。

    file_name = Path(sys.path[1]) / Path('distributed_frame_config.py')
    with (file_name).open(mode='w', encoding='utf8') as f:
        nb_print(f'在 {file_name} 目录下自动生成了一个文件, 请查看或修改 \n "{file_name}:1" 文件')
        f.write(config_file_content)
コード例 #10
0
 def __gevent_timeout_deceo(*args, **kwargs):
     timeout = gevent.Timeout(timeout_t, )
     timeout.start()
     result = None
     try:
         result = f(*args, **kwargs)
     except gevent.Timeout as t:
         logger_gevent_timeout_deco.error(f'函数 {f} 运行超过了 {timeout_t} 秒')
         if t is not timeout:
             nb_print(t)
             # raise  # not my timeout
     finally:
         timeout.close()
         return result
コード例 #11
0
 def __evenlet_timeout_deco(*args, **kwargs):
     timeout = Timeout(timeout_t, )
     # timeout.start()  # 与gevent不一样,直接start了。
     result = None
     try:
         result = f(*args, **kwargs)
     except Timeout as t:
         logger_evenlet_timeout_deco.error(
             f'函数 {f} 运行超过了 {timeout_t} 秒')
         if t is not timeout:
             nb_print(t)
             # raise  # not my timeout
     finally:
         timeout.cancel()
         return result
コード例 #12
0
def auto_creat_config_file_to_project_root_path():
    """
    在没有使用pycahrm运行代码时候,如果实在cmd 或者 linux 运行, python xx.py,
    请在临时会话窗口设置linux export PYTHONPATH=你的项目根目录 ,winwdos set PYTHONPATH=你的项目根目录
    :return:
    """
    # print(Path(sys.path[1]).as_posix())
    # print((Path(__file__).parent.parent).absolute().as_posix())
    # if Path(sys.path[1]).as_posix() in Path(__file__).parent.parent.absolute().as_posix():
    #     nb_print('不希望在本项目里面创建')
    #     return
    if '/lib/python' in sys.path[1] or r'\lib\python' in sys.path[
            1] or '.zip' in sys.path[1]:
        return  # 当没设置pythonpath时候,也不要在 /lib/python36.zip这样的地方创建配置文件。

    file_name = Path(sys.path[1]) / Path('distributed_frame_config.py')
    with (file_name).open(mode='w', encoding='utf8') as f:
        nb_print(f'在 {file_name} 目录下自动生成了一个文件, 请查看或修改 \n "{file_name}:1" 文件')
        f.write(config_file_content)
コード例 #13
0
def show_frame_config():
    nb_print('显示当前的项目中间件配置参数')
    for var_name in dir(frame_config):
        if var_name.isupper():
            var_value = getattr(frame_config, var_name)
            if var_name == 'MONGO_CONNECT_URL':
                if re.match('mongodb://.*?:.*?@.*?/.*', var_value):
                    mongo_pass = re.search('mongodb://.*?:(.*?)@', var_value).group(1)
                    mongo_pass_encryption = f'{"*" * (len(mongo_pass) - 2)}{mongo_pass[-1]}' if len(
                        mongo_pass) > 3 else mongo_pass
                    var_value_encryption = re.sub(r':(\w+)@', f':{mongo_pass_encryption}@', var_value)
                    nb_print(f'{var_name}:             {var_value_encryption}')
                    continue
            if 'PASS' in var_name and var_value is not None and len(var_value) > 3:  # 对密码打*
                nb_print(f'{var_name}:                {var_value[0]}{"*" * (len(var_value) - 2)}{var_value[-1]}')
            else:
                nb_print(f'{var_name}:                {var_value}')
    print('\n')
コード例 #14
0
    def f2(x):

        time.sleep(3)
        nb_print(x * 10)
コード例 #15
0
class CustomEventletPoolExecutor(greenpool.GreenPool):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        check_evenlet_monkey_patch()
        atexit.register(self.shutdown)

    def submit(self, *args, **kwargs):  # 保持为一直的公有用法。
        # nb_print(args)
        self.spawn_n(*args, **kwargs)
        # self.spawn_n(*args, **kwargs)

    def shutdown(self):
        self.waitall()


if __name__ == '__main__':
    # greenpool.GreenPool.waitall()
    monkey_patch(all=True)

    def f2(x):

        time.sleep(2)
        nb_print(x)

    pool = CustomEventletPoolExecutor(4)

    for i in range(15):
        nb_print(f'放入{i}')
        pool.submit(evenlet_timeout_deco(8)(f2), i)
コード例 #16
0
    def f2(x):

        time.sleep(2)
        nb_print(x)
コード例 #17
0
    return threading.active_count()


if __name__ == '__main__':
    from function_scheduling_distributed_framework.utils import decorators
    from function_scheduling_distributed_framework.concurrent_pool.bounded_threadpoolexcutor import BoundedThreadPoolExecutor

    # @decorators.keep_circulating(1)
    def f1(a):
        time.sleep(0.2)
        nb_print(f'{a} 。。。。。。。')
        # raise Exception('抛个错误测试')

    # show_current_threads_num()
    pool = CustomThreadPoolExecutor(200).set_log_level(10).set_min_workers()
    # pool = BoundedThreadPoolExecutor(200)   # 测试对比原来写的BoundedThreadPoolExecutor
    show_current_threads_num(sleep_time=5)
    for i in range(300):
        time.sleep(
            0.3
        )  # 这里的间隔时间模拟,当任务来临不密集,只需要少量线程就能搞定f1了,因为f1的消耗时间短,不需要开那么多线程,CustomThreadPoolExecutor比BoundedThreadPoolExecutor 优势之一。
        pool.submit(f1, str(i))

    nb_print(6666)
    # pool.shutdown(wait=True)
    pool.submit(f1, 'yyyy')

    # 下面测试阻塞主线程退出的情况。注释掉可以测主线程退出的情况。
    while True:
        time.sleep(10)
コード例 #18
0
 def _show_current_threads_num():
     while True:
         # logger_show_current_threads_num.info(f'{process_name} 进程 的 并发数量是 -->  {threading.active_count()}')
         nb_print(
             f'{process_name} 进程 的 线程数量是 -->  {threading.active_count()}')
         time.sleep(sleep_time)
コード例 #19
0
def use_config_form_distributed_frame_config_module():
    """
    自动读取配置。会优先读取启动脚本的目录的distributed_frame_config.py文件。没有则读取项目根目录下的distributed_frame_config.py
    :return:
    """
    current_script_path = sys.path[0].replace('\\', '/')
    project_root_path = sys.path[1].replace('\\', '/')
    inspect_msg = f"""
    分布式函数调度框架,设置配置有两种方式。两种方式的目的相同,就是使用猴子补丁的方式修改此框架的frame_config模中块的变量。
    
    1)第一种方式,自动读取配置文件方式
    分布式函数调度框架会尝试自动导入distributed_frame_config模块
    请在你的python当前项目的根目录下 {project_root_path} 或 当前文件夹 {current_script_path} 文件夹下,创建一个名为 distributed_frame_config.py 的文件,并在文件中定义例子里面的python常量。
    自动读取配置,会优先读取启动脚本的所在目录 {current_script_path} 的distributed_frame_config.py文件,
    如果没有 {current_script_path}/distributed_frame_config.py 文件,则读取项目根目录 {project_root_path} 下的distributed_frame_config.py做配置。
    内容例子如下,distributed_frame_config模块需要按需必须包含以下变量,需要按需重新设置要使用到的中间件的键和值,例如没有使用rabbitmq而是使用redis做中间件,则不需要配置rabbitmq。
    
    
    \033[0;97;40m
    MONGO_CONNECT_URL = f'mongodb://*****:*****@127.0.01:27017/admin'
    
    RABBITMQ_USER = '******'
    RABBITMQ_PASS = '******'
    RABBITMQ_HOST = '127.0.0.1'
    RABBITMQ_PORT = 5672
    RABBITMQ_VIRTUAL_HOST = 'rabbitmq_virtual_host'
    
    REDIS_HOST = '127.0.0.1'
    REDIS_PASSWORD = '******' 
    REDIS_PORT = 6379
    REDIS_DB = 7
    
    NSQD_TCP_ADDRESSES = ['127.0.0.1:4150']
    NSQD_HTTP_CLIENT_HOST = '127.0.0.1'
    NSQD_HTTP_CLIENT_PORT = 4151
    
    KAFKA_BOOTSTRAP_SERVERS = ['127.0.0.1:9092']
    
    SQLACHEMY_ENGINE_URL ='sqlite:////sqlachemy_queues/queues.db'

    ROCKETMQ_NAMESRV_ADDR = '192.168.199.202:9876'
    
    # nb_log包的第几个日志模板,内置了7个模板,可以在你当前项目根目录下的nb_log_config.py文件扩展模板。
    NB_LOG_FORMATER_INDEX_FOR_CONSUMER_AND_PUBLISHER = 7  # 7是简短的不可跳转,5是可点击跳转的
    TIMEZONE = 'Asia/Shanghai' 
    
    \033[0m
    
    \033[0;93;100m
    2)第二种方式,手动调用猴子补丁函数的方式
    如果你没有在python当前项目的根目录下 {project_root_path} 或 当前文件夹 {current_script_path} 文件夹下建立 distributed_frame_config.py 这个文件,
    也可以使用第二种配置方式,调用 patch_frame_config 函数进行框架配置设置
    \033[0m
    
    \033[0;97;40m
    from function_scheduling_distributed_framework import patch_frame_config, show_frame_config
    # 初次接触使用,可以不安装任何中间件,使用本地持久化队列。正式墙裂推荐安装rabbitmq。
    # 使用打猴子补丁的方式修改框架配置。这里为了演示,列举了所有中间件的参数,
    # 实际是只需要对使用到的中间件的配置进行赋值即可。

    patch_frame_config(MONGO_CONNECT_URL='mongodb://*****:*****@xx.90.89.xx:27016/admin',
    
                       RABBITMQ_USER='******',
                       RABBITMQ_PASS='******',
                       RABBITMQ_HOST='1xx.90.89.xx',
                       RABBITMQ_PORT=5672,
                       RABBITMQ_VIRTUAL_HOST='test_host',
    
                       REDIS_HOST='1xx.90.89.xx',
                       REDIS_PASSWORD='******',
                       REDIS_PORT=6543,
                       REDIS_DB=7,
    
                       NSQD_TCP_ADDRESSES=['xx.112.34.56:4150'],
                       NSQD_HTTP_CLIENT_HOST='12.34.56.78',
                       NSQD_HTTP_CLIENT_PORT=4151,
    
                       KAFKA_BOOTSTRAP_SERVERS=['12.34.56.78:9092'],
                       
                       SQLACHEMY_ENGINE_URL = 'mysql+pymysql://root:[email protected]:3306/sqlachemy_queues?charset=utf8',

                       ROCKETMQ_NAMESRV_ADDR = '192.168.199.202:9876',
                       
                       NB_LOG_FORMATER_INDEX_FOR_CONSUMER_AND_PUBLISHER = 7  # 7是简短的不可跳转,5是可点击跳转的
                       )

    show_frame_config()
    \033[0m
    
    """
    # sys.stdout.write(f'\033[0;33m{time.strftime("%H:%M:%S")}\033[0m  "{__file__}:{sys._getframe().f_lineno}"   \033[0;30;43m{inspect_msg}\033[0m\n')
    # noinspection PyProtectedMember
    sys.stdout.write(
        f'\033[0;93m{time.strftime("%H:%M:%S")}\033[0m  "{__file__}:{sys._getframe().f_lineno}"   \033[0;93;100m{inspect_msg}\033[0m\n'
    )

    try:
        # noinspection PyUnresolvedReferences
        # import distributed_frame_config
        m = importlib.import_module('distributed_frame_config')
        # nb_print(m.__dict__)
        nb_print(f'分布式函数调度框架 读取到\n "{m.__file__}:1" 文件里面的变量作为配置了\n')
        for var_namex, var_valuex in m.__dict__.items():
            if var_namex.isupper():
                setattr(frame_config, var_namex, var_valuex)
    except ModuleNotFoundError:
        nb_print(
            f'''分布式函数调度框架检测到 你的项目根目录 {project_root_path} 和当前文件夹 {current_script_path}  下没有 distributed_frame_config.py 文件,
                 无法使用第一种方式做配置。
                 请你务必使用第二种方式,调用 patch_frame_config 函数打猴子补丁进行框架的配置进行设置,
                 patch_frame_config 函数要放在生成消费者 发布者之前运行\n\n''')
        auto_creat_config_file_to_project_root_path()
        nb_print(
            f'在 {project_root_path} 目录下自动生成了一个文件, 请查看或修改 \n "{project_root_path}/distributed_frame_config.py:1" 文件'
        )

    show_frame_config()
コード例 #20
0
 def f1(a):
     time.sleep(0.2)
     nb_print(f'{a} 。。。。。。。')
コード例 #21
0
 def f1(a):
     time.sleep(2)  # 可修改这个数字测试多线程数量调节功能。
     nb_print(f'{a} 。。。。。。。')
     return a * 10
コード例 #22
0
    def submit(self, fn: Callable, *args, **kwargs):
        self._q.put((fn, args, kwargs))

    def joinall(self):
        gevent.joinall(self.g_list)

    def joinall_in_new_thread(self):
        threading.Thread(target=self.joinall)

    def __atexit(self):
        self.logger.critical('想即将退出程序。')
        self.joinall()


if __name__ == '__main__':
    monkey.patch_all(thread=False)

    def f2(x):

        time.sleep(3)
        nb_print(x * 10)

    pool = GeventPoolExecutor3(40)

    for i in range(20):
        time.sleep(0.1)
        nb_print(f'放入{i}')
        pool.submit(gevent_timeout_deco(8)(f2), i)
    # pool.joinall_in_new_thread()
    nb_print(66666666)
 def f1(a):
     time.sleep(0.2)  # 可修改这个数字测试多线程数量调节功能。
     nb_print(f'{a} 。。。。。。。')
コード例 #24
0
 def __init__(self, x, y, z):
     in_param = copy.deepcopy(locals())
     nb_print(f'执行初始化啦, {in_param}')