并行执行任务思考

问题

这篇文章由之前的并行执行任务发展而来,如何生成task,在之前的文章中,生成task方式如下:

Abstract Task: 
public abstract class BasicUserFilter implements Callable<UserFilterDto> {
private static final Log logger = LogFactory.getLog(BasicUserFilter.class);
@Autowired
UserService userService;
public Long companyId;
public Long userId;
@Override
public UserFilterDto call() throws Exception {
    try {
        //每个执行任务调用同一个方法,只是入参不同
        Response<Boolean> response = userService.filter(getUserId(), getCompanyId());
        if (response.isSuccess() && response.getResult()) {
            return new UserFilterDto().setCompanyId(getCompanyId()).setUserId(getUserId()).setFilterResultEnum(FilterResultEnum.TRUE);
        }
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
    return new UserFilterDto().setCompanyId(getCompanyId()).setUserId(getUserId()).setFilterResultEnum(FilterResultEnum.FALSE);
}
@PostConstruct
abstract void init();
// ... 篇幅关系,省略属性setter、getter方法
}
}

Task1:
public class Task1 extends BasicUserFilter{
    @Override
    public void init() {
        FilterConfigManager.register(CompanyAppIdEnum.GEI_NI_HUA.getCompanyId(),this);
    }
    @Override
    public UserFilterDto call() throws Exception {
        return super.call();
    }
}

上面生成任务类时,使用了策略模式,添加每一个任务都必须新增一个实体类,且实现BasicUserFilter或者重写自己的call方法,有木有比较好的方法解决这种繁琐的任务类构建呢。

方案

解决切入点,就是所有的任务类都执行了相同的逻辑,且调用了入参不同的方法而已,无疑使用代理模式去动态生成任务类,思路有了,代码实现也边的简单起来。下面使用java InvocationHandler创建动态代理类.

ProxyHandler:
/**
 * @author LiosWong
 * @description
 * @date 2018/10/27 上午1:10
 */
public class ProxyHandler<T> implements InvocationHandler, Serializable {
    private static final long serialVersionUID = -6424540398559729838L;
    private final ProxyInterface<T> proxyInterface;

    public ProxyHandler(ProxyInterface<T> proxyInterface) {
        this.proxyInterface = proxyInterface;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 根据方法名,执行不同逻辑
        if ("call".equals(method.getName())) {
            return proxyInterface.call();
        }
        return null;
    }
}
ProxyInterface:为了使代理模版通用,添加接口约束
/** 
 * @author LiosWong
 * @description 可扩展代理接入点
 * @date 2018/10/27 上午1:11
 */
public interface ProxyInterface<T> extends Callable<T> {

}
ProxyFactory:代理工厂
public class ProxyFactory<T> {
private final Class<T> mapperInterface;

public ProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
    return mapperInterface;
}
@SuppressWarnings("unchecked")
protected T newInstance(ProxyHandler<T> mapperProxy) {
    return (T) java.lang.reflect.Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
}
public T newInstance(ProxyInterface proxyInterface) {
    final ProxyHandler<T> mapperProxy = new ProxyHandler<T>(proxyInterface);
    return newInstance(mapperProxy);
}
}

完成了上面的动态代理类构建,下面就是在业务代码中使用:

 ProxyFactory proxyFactory = new ProxyFactory<Callable>(Callable.class);
        List<Callable<UserFilterDto>> callableList = new ArrayList<>();
        List<UserFilterDto> filterDtosResult = new ArrayList<>();
        // 动态生成代理类
        list.forEach(p -> {
            Callable<UserFilterDto> callable = null;
            // 复用代理模版
            switch (concurrencyType) {
                case FILTER:
                    callable = (Callable<UserFilterDto>) proxyFactory.newInstance(new ProxyFilterCallable(xjUserService, userId, p.getCompanyId()));
                    break;
                case SATISFY:
                    callable = (Callable<UserFilterDto>) proxyFactory.newInstance(new ProxySatisfyCallable(companyUserGroupService, userId, p.getCompanyId()));
                    break;
                default:
                    break;
            }
            callableList.add(callable);
        });

ProxyFilterCallable:

public class ProxyFilterCallable<T> implements ProxyInterface<T> {
    private static final Log logger = LogFactory.getLog(ProxyFilterCallable.class);
    private UserService userService;
    private Long userId;
    private Long companyId;

    public ProxyFilterCallable(XjUserService xjUserService, Long userId, Long companyId) {
        this.xjUserService = xjUserService;
        this.userId = userId;
        this.companyId = companyId;
    }
    @Override
    public T call() throws Exception {
        try {
            Response<Boolean> response = userService.filter(getUserId(), getCompanyId());
            if (response.isSuccess() && response.getResult()) {
                return (T) new UserFilterDto().setCompanyId(getCompanyId()).setUserId(getUserId()).setFilterResultEnum(FilterResultEnum.TRUE);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return (T) new UserFilterDto().setCompanyId(getCompanyId()).setUserId(getUserId()).setFilterResultEnum(FilterResultEnum.FALSE);
    }
    // ...
}

ProxySatisfyCallable:

public class ProxySatisfyCallable<T> implements ProxyInterface<T> {
    private static final Log logger = LogFactory.getLog(ProxyFilterCallable.class);
    private CompanyUserGroupService companyUserGroupService;
    private Long userId;
    private Long companyId;

    public ProxySatisfyCallable(CompanyUserGroupService companyUserGroupService, Long userId, Long companyId) {
        this.companyUserGroupService = companyUserGroupService;
        this.userId = userId;
        this.companyId = companyId;
    }

    @Override
    public T call() throws Exception {
        try {
            XjFilterUserResultVo xjFilterUserResultVo = companyUserGroupService.checkUserInfoIsSatisfyCompany(getUserId(), getCompanyId());
            if (Objects.nonNull(xjFilterUserResultVo) && xjFilterUserResultVo.getResult()) {
                return (T) new UserFilterDto().setCompanyId(getCompanyId()).setUserId(getUserId()).setFilterResultEnum(FilterResultEnum.TRUE);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return (T) new UserFilterDto().setCompanyId(getCompanyId()).setUserId(getUserId()).setFilterResultEnum(FilterResultEnum.FALSE);
    }
    // ...
}

<think>好的,我现在要解决用户的问题:如何在Python中使用schedule库设置同一时间点并行执行两个不同的任务。首先,我需要回顾一下schedule库的基本用法,它通常用于定时任务的调度,但默认情况下是串行执行的,也就是说任务会按顺序一个接一个地运行,即使它们的触发时间相同。 用户提到的是“并行执行”,这意味着两个任务需要在同一时间点同时运行,而不是依次执行。这时候我需要考虑Python中的并发执行机制。Python有几种处理并发的方式,比如多线程、多进程或者异步IO。由于schedule库本身是同步的,可能需要结合这些并发方法来实现并行。 首先,我应该检查schedule库是否本身支持并行任务。查阅文档后发现,schedule默认情况下是不支持并行的,因为它的设计是单线程的,任务按顺序执行。当一个任务运行时,其他任务必须等待当前任务完成才能执行。因此,如果两个任务在同一时间点被触发,第二个任务会等到第一个任务完成后才开始,这显然不符合用户的需求。 接下来,我需要思考如何修改这个行为。可能的解决方案是将每个任务放入单独的线程中,这样即使主线程中的schedule是顺序执行的,每个任务在自己的线程里运行,从而实现并行效果。不过,需要注意Python的全局解释器锁(GIL)可能会影响多线程的并行性能,但对于IO密集型任务,多线程仍然有效。如果是CPU密集型任务,可能需要考虑多进程。 于是,具体的步骤可能包括: 1. 使用schedule库安排两个任务在同一时间触发。 2. 每个任务函数在被调用时,启动一个新的线程来执行实际的任务代码。 3. 确保主线程持续运行,以便schedule能够检查任务触发时间。 然后,我需要验证这个思路是否正确。比如,编写一个示例代码,创建两个函数task1和task2,分别用线程来执行。然后使用schedule每隔一段时间(比如每天10点)运行这两个函数。在函数内部,使用threading.Thread来启动任务,这样即使task1和task2被同时触发,它们也会在各自的线程中运行,从而并行执行。 另外,还需要注意线程的管理,比如是否需要在任务完成后回收线程资源,或者处理可能的异常。但基本的示例可能不需要这些复杂的处理,用户可能只需要一个简单的并行执行机制。 可能的代码结构大致如下: - 导入schedule和threading模块。 - 定义任务函数,内部使用线程来执行实际代码。 - 安排这两个任务在同一个时间点触发。 - 使用一个循环来持续运行schedule的检查。 此外,还需要提醒用户关于GIL的限制,以及如果任务需要大量CPU计算,考虑使用multiprocessing模块替代多线程。不过,在大多数情况下,尤其是涉及网络请求或文件操作的IO密集型任务,多线程已经足够。 最后,测试这个代码是否真的能并行执行。比如,在两个任务中分别打印开始和结束的时间,观察是否有重叠的执行时间段。如果时间重叠,说明并行成功。 总结下来,解决方案的核心是结合schedule进行任务调度,同时利用线程来实现每个任务并行执行。</think>在Python中,`schedule`库本身不支持真正的并行执行(因其基于单线程轮询机制),但可通过多线程实现近似并行效果。以下是分步实现方法: --- ### **1. 安装库** ```bash pip install schedule ``` --- ### **2. 实现思路** - **多线程**:每个任务包裹独立线程 - **定时触发**:用`schedule`设置相同触发时间 - **主循环守护**:保持主线程持续运行 --- ### **3. 完整代码示例** ```python import schedule import time import threading def task1(): def job(): print(f"[{time.strftime('%H:%M:%S')}] Task1开始执行") time.sleep(5) # 模拟耗时操作 print(f"[{time.strftime('%H:%M:%S')}] Task1执行完毕") threading.Thread(target=job, daemon=True).start() def task2(): def job(): print(f"[{time.strftime('%H:%M:%S')}] Task2开始执行") time.sleep(3) # 模拟耗时操作 print(f"[{time.strftime('%H:%M:%S')}] Task2执行完毕") threading.Thread(target=job, daemon=True).start() # 设置每天10:30同时执行两个任务 schedule.every().day.at("10:30").do(task1) schedule.every().day.at("10:30").do(task2) while True: schedule.run_pending() time.sleep(1) ``` --- ### **4. 关键说明** 1. **线程封装**:每个任务通过`threading.Thread`启动独立线程执行实际代码 2. **daemon=True**:确保主线程退出时子线程自动终止 3. **执行结果示例**: ``` [10:30:00] Task1开始执行 [10:30:00] Task2开始执行 [10:30:03] Task2执行完毕 [10:30:05] Task1执行完毕 ``` 可见两个任务在同一时间启动并**并行执行** --- ### **5. 注意事项** - **GIL限制**:CPU密集型任务建议改用`multiprocessing`模块 - **资源竞争**:若任务共享资源,需添加线程锁(`threading.Lock`) - **异常处理**:建议在`job()`函数内添加`try...except` --- 通过以上方法,即可实现同一时间点并行执行不同任务的需求。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值