精华内容
下载资源
问答
  • 任务失败试机制某些场景下业务失败需要试,比如说状态通知第三方,发奖品,发短信等等。...方案一具有HA,但实现与机器相关的业务场景比较难,比如某台机器缓存更新失败,需要稍后试,而且引入的依赖会很多

    任务失败重试机制

    某些场景下业务失败需要重试,比如说状态通知第三方,发奖品,发短信等等。总体的思路是将任任务现场记录下来,然后稍后重试。方案有多种

    • 任务现场存储在db中,使用分布式任务调度统一去执行。
    • 任务现场存储在文件中, 各自重试。

    方案二的依赖少,而且能做到各个机器的隔离,但是没有HA。方案一具有HA,但实现与机器相关的业务场景比较难,比如某台机器缓存更新失败,需要稍后重试,而且引入的依赖会很多。考虑到机器的故障率不高,且为了尽量减少依赖,采用了方案二。

    本地持久化队列实现任务失败重试

    使用了Berkeley DB实现了本地持久化队列。 每个任务需要指定berkeleydb的存储路径,以及任务的名字。框架封装了底层的持久化队列,对外只暴露失败执行策略和失败执行的业务处理回调。使用的设计模式是组合+策略

    • RetryPolicy: 定义任务是否要执行,执行的频率。 这个可以复用
    • RetryCallBack: 定义任务重试时 实际要执行的业务逻辑。

    例子

    /**
     * Created by carey on 2017/9/20 11:14:46.
     */
    public class ExampleRetryManager {
    
        /**
         * spring使用方式就用属性注入
         */
        private String taskSaveLocation = "/tmp/project/retryTask";
    
        /**
         * spring使用方式就用属性注入
         */
        private String taskDbName = "taskName";
    
        private RetryTemplate<ExampleTaskParam> retryTemplate;
    
    
        /**
         * 必须要调用的初始化方法
         * spring使用方式就用PostConstruct
         */
        public void init() {
            retryTemplate = new RetryTemplate<ExampleTaskParam>(
                    new RetryCallBack<ExampleTaskParam>() {
                        @Override
                        public boolean doRetry(TaskContext<ExampleTaskParam> taskContext) {
                            ExampleTaskParam taskPacket = taskContext.getTaskParam();
                            return false;
                        }
                    },
                    new ExampleRetryPolicy<ExampleTaskParam>(),
                    taskSaveLocation,
                    "test");
    
            retryTemplate.init();
        }
    
    
        /**
         * 增加重试任务
         * @param taskContext
         */
        public void addRetry(TaskContext<ExampleTaskParam> taskContext) {
            retryTemplate.addTask(taskContext);
        }
    
    }
    
    
    /**
     * 注意数组越界错误
     * @param <T>
     */
    class ExampleRetryPolicy<T extends Serializable> implements RetryPolicy<T> {
    
        private static int[] RETRY_DELAY_MINS = {1, 1, 1, 1, 1, 1, 1, 1};
    
        @Override
        public boolean isValid(TaskContext<T> taskContext) {
            return taskContext != null && taskContext.getCurExecuteCnt() < RETRY_DELAY_MINS.length - 1;
        }
    
        @Override
        public boolean isReady(TaskContext<T> taskContext) {
            return taskContext.getNextExecuteTime() < new Date().getTime();
        }
    
        @Override
        public long getNextExecuteTime(TaskContext<T> taskContext) {
            long timeDelay = RETRY_DELAY_MINS[taskContext.getCurExecuteCnt()] * 1000 * 60;
            return new Date().getTime() + timeDelay;
        }
    }
    

    任务对象参数

    /**
     *
     * 必须要实现序列化接口
     * Created by carey on 2017/9/20 11:15:01.
     */
    public class ExampleTaskParam implements Serializable {
        private static final long serialVersionUID = -8624662207361962314L;
    
        private int a;
        private String b;
    
        @Override
        public String toString() {
            return "TestRetryDo{" +
                    "a=" + a +
                    ", b='" + b + '\'' +
                    '}';
        }
    
        public int getA() {
            return a;
        }
    
        public void setA(int a) {
            this.a = a;
        }
    
        public String getB() {
            return b;
        }
    
        public void setB(String b) {
            this.b = b;
        }
    }
    

    注意事项

    • 任务参数必须要实现序列化接口,这个框架已经实现
    • 任务参数对象在放入队列后,再去修改参数,是不会修改到队列中的参数(这个时候就已经序列化存储到文件中)
    • 不同的任务会使用不同的任务参数,在构造任务管理类的时候需要保证不同任务使用不同的任务名字,否则会出现castException.(后面框架会保证同一个env环境路径下的相同的任务名称只能对应一个taskParam的类型)

    底层实现

    1. 对于Berkeley DB的管理,由于一个berkeley DB的一个env环境可以管理多个db,在关闭db的时候通常需要关闭db。在一个env管理db1和db2时,如果当db1关闭时,同时关闭了env,那么db2也将无法使用,所以提供了一个工厂类统一管理env和db。在所有的db都关闭时,才会关闭env。
    2. 将重试任务管理成一个队列,使用berkeleyDB mapview的特性

    具体的代码:env包装类

        /**
         * 单例工厂模式  同一个env下可以可以管理多个db
         * 避免同一个路径下同时创建多个env
         * Author: yuncong
         * Author: carey
         * Created at: 2012-8-6 13:22:12
         */
        public class BdbEnvironment {
            private static final String CLASS_CATALOG = "java_class_catalog";
    
            private Environment environment;
            //这个db单独存储类型信息,通过javaCataLog暴露出去给外部
            private Database catalogDb;
            private StoredClassCatalog javaCatalog;
    
            private static Map<String, BdbEnvironment> envs = new ConcurrentHashMap<>();
    
    
            public BdbEnvironment(String envHome)
                    throws DatabaseException {
                File home = new File(envHome);
                if (!home.exists()) {
                    boolean success = home.mkdirs();
                    if (!success) {
                        throw new RuntimeException();
                    }
                }
    
                try {
                    EnvironmentConfig environmentConfig = new EnvironmentConfig();
                    environmentConfig.setTransactional(true);
                    environmentConfig.setAllowCreate(true);
    
                    environmentConfig.setDurability(Durability.COMMIT_WRITE_NO_SYNC);
    
                    environment = new Environment(home, environmentConfig);
    
                    DatabaseConfig dbConfig = new DatabaseConfig();
                    dbConfig.setTransactional(true);
                    dbConfig.setAllowCreate(true);
    
                    catalogDb = environment.openDatabase(null, CLASS_CATALOG, dbConfig);
                    javaCatalog = new StoredClassCatalog(catalogDb);
    
                } catch (DatabaseException dbe) {
                    throw new RuntimeException();
                }
            }
    
    
            /**
             * 关闭单个环境
             */
            public void close() {
                if (catalogDb != null) catalogDb.close();
                if (javaCatalog != null) javaCatalog.close();
                if (environment != null) environment.close();
            }
    
            public Environment getEnvironment() {
                return environment;
            }
    
            public StoredClassCatalog getJavaCatalog() {
                return javaCatalog;
            }
        }
    

    任务队列抽象

        /**
         * 基于 Berkeley DB 的持久化队列 并非是标准化的java队列
         * 1. 不允许直接清空
         * 
         * Created by carey on 2017/9/8.
         */
        public class BdbQueue<E extends Serializable> extends AbstractQueue<E> {
    
            private BdbEnvironment bdbEnvironment;
    
            private Database queueDb;             // 数据库,用于保存值,使得支持队列持久化,无需序列化
    
            /**
             * Thread safe?
             */
            private StoredSortedMap<Long, E> queueMap;   //持久化Map,Key为指针位置,Value为值,
    
            private TransactionRunner transactionRunner;
    
            /**
             * 队列的名字,不同队列的名字就相当于不同的表
             */
            private String queueName = "";
    
    
            private Object syncObj = new Object();
    
    
            private static final String MESSAGE_STORE = "message_store";
    
    
            /**
             * 构造方法
             * @param environment bdb环境配置
             * @param dbName  db的名字  一个db对应一个queue
             */
            BdbQueue(BdbEnvironment environment, String dbName) {
                DatabaseConfig dbConfig = new DatabaseConfig();
                dbConfig.setTransactional(true);
                dbConfig.setAllowCreate(true);
    
                this.bdbEnvironment = environment;
                this.queueName = dbName;
                queueDb = bdbEnvironment.getEnvironment().openDatabase(null, MESSAGE_STORE + this.getQueueName(), dbConfig);
    
                EntryBinding messageKeyBinding = new SerialBinding<Long>(bdbEnvironment.getJavaCatalog(), Long.class);
                EntryBinding messageValueBinding = new SerialBinding<Object>(bdbEnvironment.getJavaCatalog(), Object.class);
    
                queueMap = new StoredSortedMap(queueDb, messageKeyBinding, messageValueBinding, true);
                transactionRunner = new TransactionRunner(bdbEnvironment.getEnvironment());
            }
    
    
            /**
             *
             */
            public void close() {
                if (queueDb != null)
                    queueDb.close();
            }
    
    
            @Override
            public Iterator<E> iterator() {
                return queueMap.values().iterator();
            }
    
            @Override
            public int size() {
                return queueMap.size();
            }
    
            @Override
            public boolean offer(E e) {
                if (null == e) {
                    throw new IllegalArgumentException("原始不允许为空");
                }
                synchronized (syncObj) {
                    Long lastKey = queueMap.lastKey();
                    lastKey = (lastKey == null) ? 1L : lastKey + 1L;
                    queueMap.put(lastKey, e);
                }
                return true;
            }
    
    
            @Override
            public E poll() {
                synchronized (syncObj) {
                    Long firstKey;
                    E val;
                    if ((firstKey = queueMap.firstKey()) == null || (val = queueMap.get(firstKey)) == null) {
                        return null;
                    }
                    return queueMap.remove(firstKey);
                }
            }
    
            @Override
            public E peek() {
                synchronized (syncObj) {
                    Long firstKey;
                    E val;
                    if ((firstKey = queueMap.firstKey()) == null || (val = queueMap.get(firstKey)) == null) {
                        return null;
                    }
                    return val;
                }
            }
    
            @Override
            public void clear() {
                throw new UnsupportedOperationException();
            }
    
            public Database getQueueDb() {
                return queueDb;
            }
    
    
            public StoredSortedMap<Long, E> getQueueMap() {
                return queueMap;
            }
    
    
            public String getQueueName() {
                return queueName;
            }
    
            public BdbEnvironment getBdbEnvironment() {
                return bdbEnvironment;
            }
    
            public TransactionRunner getTransactionRunner() {
                return transactionRunner;
        }
    }   
    

    任务队列工厂

    /**
     * Created by carey on 2017/9/19 15:17:46.
     */
    public class BdbQueueFactory {
    
        private static ConcurrentHashMap<String/*envPath*/, BdbEnvironment> bdbEnvironments = new ConcurrentHashMap<>();
    
        private static ConcurrentHashMap<String/*envPath*/, Map<String/*dbName*/, BdbQueue>> env2QueuesMap = new ConcurrentHashMap<>();
    
    
        private static Object staticSyncObj = new Object();
    
    
        private static Logger logger = LoggerFactory.getLogger(BdbQueueFactory.class);
    
        static {
            Runtime.getRuntime().addShutdownHook(new Thread() {
                @Override
                public void run() {
                    closeAll();
                }
            });
        }
    
    
    
        public static  BdbQueue getQueue(String envPath, String queueName) {
            Map<String/*queueName*/, BdbQueue> queueMap = env2QueuesMap.get(envPath);
            if (null != queueMap) {
                BdbQueue queue = queueMap.get(queueName);
                if (null != queue) {
                    return queue;
                }
            }
    
            synchronized (staticSyncObj) {
                queueMap = env2QueuesMap.get(envPath);
                if (null != queueMap) {
                    BdbQueue queue = queueMap.get(queueName);
                    if (null != queue) {
                        return queue;
                    }
                }
                //如果环境的路径的共用
                BdbEnvironment bdbEnvironment = bdbEnvironments.get(envPath);
                if (bdbEnvironment == null) {
                    bdbEnvironment = new BdbEnvironment(envPath);
                    bdbEnvironments.put(envPath, bdbEnvironment);
                    env2QueuesMap.put(envPath, new ConcurrentHashMap<String, BdbQueue>());
                }
                BdbQueue queue =  new BdbQueue(bdbEnvironment, queueName);
                env2QueuesMap.get(envPath).put(queueName, queue);
                return queue;
            }
    
        }
    
    
        /**
         * 清理工作
         */
        private static void closeAll() {
            for (Map.Entry<String/*envPath*/, Map<String/*dbName*/, BdbQueue>> queueMapEntry : env2QueuesMap.entrySet()) {
                Map<String, BdbQueue> queueMap = queueMapEntry.getValue();
                for (Map.Entry<String, BdbQueue> tmp : queueMap.entrySet()) {
                    String queueName = tmp.getKey();
                    BdbQueue queue = tmp.getValue();
                    try {
                        queue.close();
                        logger.info("queue:{} close success", queueName);
                    } catch (Exception e) {
                        logger.error("queue:{} close error ", queueName, e);
                    }
                }
                String envPath = queueMapEntry.getKey();
                BdbEnvironment environment = bdbEnvironments.get(envPath);
                try{
                    environment.close();
                    logger.info("environment path:{} close success", envPath);
                }catch(Exception e) {
                    logger.error("environment path:{} close error", envPath, e);
                }
            }
    
        }
    }           
    

    真正的任务队列抽象

    /**
     * 在没有任务的情况下一直自旋,等待任务入队的唤醒
     * Created by carey on 2017/9/13.
     */
    public class RetryTemplate<T extends Serializable> {
    
    
        private BdbQueue<TaskContext<T>> taskQueue;
    
        private volatile boolean running = true;
    
        private AtomicBoolean isInited = new AtomicBoolean(false);
    
        private final RetryCallBack<T> retryCallBack;
    
        private final RetryPolicy<T> retryPolicy;
    
        private final String envPath;
        private final String queueName;
    
    
        private Object syncObj = new Object();
    
        protected Logger logger = LoggerFactory.getLogger(this.getClass());
    
        public RetryTemplate(RetryCallBack<T> retryCallBack,
                             RetryPolicy<T> retryPolicy,
                             String envPath,
                             String queueName) {
            if (StringUtils.isEmpty(envPath) || StringUtils.isEmpty(queueName)) {
                throw new IllegalArgumentException("envPath or queueName should not be null");
            }
            if (null == retryCallBack || null == retryPolicy) {
                throw new IllegalArgumentException("retryCallBack or retryCallBack should not be null");
            }
            this.retryPolicy = retryPolicy;
            this.retryCallBack = retryCallBack;
            this.envPath = envPath;
            this.queueName = queueName;
        }
    
    
        /**
         * 初始化方法,子类必须要调用
         *
         */
        public void init() {
            if (!isInited.compareAndSet(false, true)) {
                logger.info("{} has already inited", this.getClass());
                return;
            }
    
            taskQueue = BdbQueueFactory.getQueue(envPath, queueName);
            Thread retryThread = new Thread(new RetryWorker());
            retryThread.setDaemon(true);
            retryThread.setName(queueName);
            retryThread.start();
    
            registerShutdownHook();
        }
    
        private void registerShutdownHook() {
            Runtime.getRuntime().addShutdownHook(new Thread() {
                @Override
                public void run() {
                    running = false;
                }
            });
        }
    
    
        private class RetryWorker implements Runnable {
            @Override
            public void run() {
                while (running) {
                    {
                        sleep(500);
                        TaskContext<T> taskContext = waitUntilGetTask();
                        if(!retryPolicy.isValid(taskContext)) {
                            logger.info("taskContext:{} is inValid, ignore", taskContext );
                            continue;
                        }
    
                        // 执行时间还没到,再次放入队列
                        if (!retryPolicy.isReady(taskContext)) {
                            addTask(taskContext);
                            continue;
                        }
    
                        try {
                            boolean isRetrySuc = retryCallBack.doRetry(taskContext);
                            logger.info("执行任务,结果:{} 任务现场:{}", isRetrySuc, taskContext);
                            if (!isRetrySuc) {
                                tryAgainWhenFailed(taskContext);
                                logger.info("任务执行失败,重新加入队列,任务现场为:{}", taskContext);
                            }
                        } catch (Exception e) {
                            logger.error("执行重试任务失败, 任务现场:{}", taskContext, e);
                            tryAgainWhenFailed(taskContext);
                            logger.info("任务执行异常,重新加入队列,任务现场为:{}", taskContext);
                        }
                    }
                }
            }
        }
    
        /**
         * 失败时重试
         * 1. 更新任务现场
         * 2. 重新入队
         *
         * @param taskContext
         */
        private void tryAgainWhenFailed(TaskContext<T> taskContext) {
            long nextExecuteTime = retryPolicy.getNextExecuteTime(taskContext);
            taskContext.setNextExecuteTime(nextExecuteTime);
            taskContext.setCurExecuteCnt(taskContext.getCurExecuteCnt() + 1);
            addTask(taskContext);
        }
    
    
        private void sleep(long ms) {
            try {
                Thread.sleep(ms);
            } catch (InterruptedException e) {
                logger.error("中断异常", e);
            }
        }
    
        /**
         * 自旋 直到获取到任务
         *
         * @return
         */
        private TaskContext<T> waitUntilGetTask() {
            TaskContext<T> taskPacket;
            synchronized (syncObj) {
                while ((taskPacket = taskQueue.poll()) == null) {
                    try {
                        syncObj.wait();
                    } catch (InterruptedException e) {
                        logger.error("中断异常", e);
                    }
                }
            }
            return taskPacket;
        }
    
        /**
         * 增加任务
         *
         * @param taskPacket
         */
        public void addTask(TaskContext<T> taskPacket) {
            if (null == taskPacket) {
                throw new IllegalArgumentException("taskPacket should not be null");
            }
            synchronized (syncObj) {
                taskQueue.offer(taskPacket);
                syncObj.notify();
            }
        }
    }
    

    任务现场定义

    /**
     * 任务现场描述
     * Created by carey on 2017/9/15 17:45:53.
     */
    public class TaskContext<T extends Serializable> implements Serializable {
        private static final long serialVersionUID = -5568412953853536289L;
    
        /**
         * 期望的下次执行时间,不到期望时间不会执行
         * 不保证到了执行时间立即执行
         */
        private long nextExecuteTime;
    
    
        /**
         * 当前被执行的次数
         */
        private int curExecuteCnt;
    
        /**
         * 任务的具体参数
         */
        private T taskParam;
    
    
        public long getNextExecuteTime() {
            return nextExecuteTime;
        }
    
        public void setNextExecuteTime(long nextExecuteTime) {
            this.nextExecuteTime = nextExecuteTime;
        }
    
        public int getCurExecuteCnt() {
            return curExecuteCnt;
        }
    
        public void setCurExecuteCnt(int curExecuteCnt) {
            this.curExecuteCnt = curExecuteCnt;
        }
    
        public T getTaskParam() {
            return taskParam;
        }
    
        public void setTaskParam(T taskParam) {
            this.taskParam = taskParam;
        }
    
        @Override
        public String toString() {
            return "TaskContext{" +
                    "nextExecuteTime=" + nextExecuteTime +
                    ", curExecuteCnt=" + curExecuteCnt +
                    ", taskParam=" + taskParam +
                    '}';
        }
    }
    

    回调重试定义

    /**
     * 回调重试
     * Created by carey on 2017/9/19 17:14:00.
     */
    public interface RetryCallBack<T extends Serializable> {
    
        boolean doRetry(TaskContext<T> taskParam);
    }
    

    回调重试策略定义

    /**
     * Created by carey on 2017/9/19 17:16:02.
     */
    public interface RetryPolicy<T extends Serializable> {
    
        /**
         * 任务是否还有效,如果无效 直接丢弃
         * 请注意判空
         * @param taskContext
         * @return
         */
        boolean isValid(TaskContext<T> taskContext);
    
        /**
         * 是否到了执行时间
         * @param taskContext
         * @return
         */
        boolean isReady(TaskContext<T> taskContext);
    
        /**
         * 失败的时候更新下一次的执行时间
         *
         * @param taskContext
         * @return
         */
        long getNextExecuteTime(TaskContext<T> taskContext);
    
        /**
         * 默认的降幂策略
         * @param <T>
         */
        class DefaultDescending<T extends Serializable> implements RetryPolicy<T> {
    
            private static int[] RETRY_DELAY_MINS = {1, 2, 4, 8, 16, 32, 64, 128};
    
            @Override
            public boolean isValid(TaskContext<T> taskContext) {
                return taskContext != null && taskContext.getCurExecuteCnt() < RETRY_DELAY_MINS.length - 1;
            }
    
            @Override
            public boolean isReady(TaskContext<T> taskContext) {
                return taskContext.getNextExecuteTime() < new Date().getTime();
    
            }
    
            @Override
            public long getNextExecuteTime(TaskContext<T> taskContext) {
                long timeDelay =  RETRY_DELAY_MINS[taskContext.getCurExecuteCnt()] * 1000 * 60;
                return new Date().getTime() + timeDelay;
            }
        }
    }
    

    需要的依赖

    <dependency>
        <groupId>com.sleepycat</groupId>
        <artifactId>je</artifactId>
        <version>5.0.73</version>
    </dependency>
    

    最后发一波广告

    曹操专车招java开发,技术专家,架构师and so on..
    坐标: 杭州
    内推地址: yu.teng1@geely.com

    展开全文
  • 时间紧,任务重

    2011-02-18 22:08:00
    最近一段时间单位事情比较多,时间紧,任务重!呵呵,开个玩笑,都是一些琐碎的事情。单位轮岗的制度的实行,慢慢激发了不少人的学习兴趣,中心的学习气氛也浓郁起来。不过人员的变动也增加大家讲课和学习的任务。...

         最近一段时间单位事情比较多,时间紧,任务重!呵呵,开个玩笑,都是一些琐碎的事情。单位轮岗的制度的实行,慢慢激发了不少人的学习兴趣,中心的学习气氛也浓郁起来。不过人员的变动也增加大家讲课和学习的任务。其实隔行如隔山,换一个岗位还是需要一段的时间来适应的。

       时间紧,任务重的直接后果是回老家的机会少了,不能每个星期的都回去,可是小宝在父母家里带着,每周不回去看看,总感觉好像少做了一件很重要的事情,做什么事情都没有精神。小宝在家里过的很开心,并不在乎爸爸妈妈每周来看他、陪他玩。小孩子,心智单纯,还不知道什么是亲情,什么是想念,这也许是小孩子为什么能睡得那么沉的原因。小宝现在每夜还要喝二次奶,12点,4点。到时间了,只要你冲好奶,往嘴边一放,小宝就闭着眼睛吃吃的喝,小手把奶瓶抓得紧紧的,偶尔会微微睁开一点眼睛,看看是谁在喂他,然后就放心的喝起来,喝完奶,再喝点水,就又沉沉地睡去了。回去的少了,想的就多了。人真是很奇怪,年轻的时候向往自由,天天往外跑,长大了反而向往家庭了,一有机会就想回家。要是人能在刚出生的时候就能明白这些道理就好了。

         好了不浪费时间了,今天多做点实验,下个星期就可以节约时间回家了。小宝,是不是又想出去玩啊?

    转载于:https://www.cnblogs.com/sopost/archive/2011/02/18/2190049.html

    展开全文
  • 在任务之中 ,有些实时任务比较重的需求,需要在类似 iOS viewDidAppear 里面执行数据请求任务,如:上一个页面返回pop 后执行网络请求任务。在flutter中如何实现呢? 目前 flutter生命周期 里面只有 initState ,...

    前言

       在任务之中 ,有些实时任务比较重的需求,需要在类似 iOS viewDidAppear 里面执行数据请求任务,如:上一个页面返回pop 后执行网络请求任务。在flutter中如何实现呢?  目前 flutter生命周期 里面只有 initState ,没有类似iOS 编程模式的那样生命周期; 因此我们只能退而求其次的完成任务。

     

    实现

    在Navigator....then 后面执行任务,then 是 上一个页面执行pop 后才触发

    代码如下:

    Navigator.of(context).pushNamed(item.linkUrl).then((e) => RKToast.show("GO back", context));

     

    转载于:https://www.cnblogs.com/kingbo/p/11310106.html

    展开全文
  • 论文研究-多重不确定因素影响下的高端装备研制任务流程优化.pdf, ...最后,以某无人机研制任务为例进行应用研究,并把本文的优化结果与文献中的数据进行比较,检验了本文方法的有效性和优越性.
  • 最近笔试面试过程中,遇到了很多关于操作系统的问题(CPU多用户抢占机制,何为软中断等),作为一名计算机科学与技术专业的学生,我也曾学习过微机原理、...现在我想拾这些,打牢基础,绝不做空中楼阁!坚持!加油!

    中断方式与轮询方式比较

    中断的基本概念

    程序中断通常简称中断,是指CPU在正常运行程序的过程中,由于预选安排或发生了各种随机的内部或外部事件,使CPU中断正在运行的程序,而转到为相应的服务程序去处理,这个过程称为程序中断。

    二、80x86微处理器的中断 80x86微处理器的中断类型一般分为2类,即由于执行某些指令引起的软中断和由处理器以外其他控制电路发出中断请求信号引起的硬中断。 CPU要从主程序转入中断服务程序,必须知道该中断服务程序的入口地址,即中断向量。80x86CPUPC机共有256个中断向量。

    中断的一般过程:

    主程序只是在设备ABC数据准备就绪时,才去处理AC,进行数据交换。在速度较慢的外围设备准备自己的数据时,CPU照常执行自己的主程序 。在这个意义上说,CPU和外围设备的一些操作是并行地进行的,因而同串行进行的程序查询方式相比,计算机系统的效率是大大提高了。如下图:

     

        实际的中断过程还要复杂一些,下图示出了中断处理过程的详细流程图.当CPU执行完条现行指令时,如果外设向CPU发出中断请求、那么CPU在满足响应条件的情况下,将发出中断响应信号,与此同时关闭中断(“中断屏蔽触发器置“1”),表示CPU不再受理另外个设备的中断。这时、CPU将寻找中断请求源是哪个设备。并保存CPU自己的程序计数器(Pc)的内容.然后,它将转移到处理该中断源的中断服务程序.CPU在保存现场信息,设备(如文换数据)以后.将恢复现场信息.在这些动作完成以后,开放中断(“中断屏蔽触发器置‘o”),并返网到原来被中断的主程序的下一条指令。

     

    (1) 尽管外界中断请求是随机的,但CPU只有在当前一条指令执行完毕后,即转入公操作时才受理设备的中断请求,这样才不致于使当前指令的执行受到干扰。公操作是指一条指令执行结束后CPU所进行的操作,如中断处理、直接内存传送、取下条指令等 。外界中断请求信号通常存放在接口中的中断源锁存器里,并通过中断请求线连至CPU,每当一条指令执行到末尾,CPU便检查中断请求信号。若中断请求信号为“1”,则CPU转入“ 中断周期,受理外界中断。(2) 为了在中断服务程序执行完毕以后正确地返回到原来主程序被中断的断点(PC内容)而继续执行主程序,必须把程序计数器PC的内容,以及当前指令执行结束后CPU的状态(包括寄存器的内容和一些状态标志位)都保存到堆栈中去。这些操作叫做保存现场。(3) CPU响应中断后,正要去执行中断服务程序时,可能有另一个新的中断源向它发出中断请求。为了不致造成混乱,在CPU的中断管理部件中必须有一个中断屏蔽触发器,它可以在程序的控制下置“1”(设置屏蔽),或置“0”(取掉屏蔽)。只有在中断屏蔽标志为“0”时,CPU才可以受理中断。当一条指令执行完毕CPU接受中断请求并作出响应时,它一方面发出中断响应信号INTA,另一方面把中断屏蔽标志置“1”,即关闭中断。这样,CPU不能再受理另外的新的中断源发来的中断请求。只有在CPU把中断服务程序执行完毕以后,它才重新使中断屏蔽标志置“0”,即开放中断,并返回主程序。因此,中断服务程序的最后必须有两条指令,即开中断指令和返主指令,同时在硬件上要保证返主指令执行以后才受理新的中断请求。(4) 中断处理过程是由硬件和软件结合来完成的。如在前图中,中断周期由硬件实现,而中断服务程序由机器指令序列实现。后者除执行保存现场、恢复现场、开放中断并返回主程序任务外,对要求中断的设备进行服务,使其同CPU交换一个字的数据,或作其他服务。

    轮询方式的基本概念

    轮询(Polling)IO方式或程序控制IO方式,是让CPU以一定的周期按次序查询每一个外设,看它是否有数据输入或输出的要求,若有,则进行相应的输入/输出服务;若无,或IO处理完毕柏,CPU就接着查询下一个外设。

    所需硬件:外设接口提供状态端口、数据端口

    软件机制:应用程序必须定时查询各个接口的状态端口,判断是否需要输入、输出数据,如果需要,则通过数据端口进行数据操作。

    特点:CPU通过执行指令主动对外部设备进行查询,外部设备处于被动地位

     

    上图为一般过程。

    轮询方式与中断方式的比较

    速度

    程序控制方式:

    硬件的速度指标:由于程序控制方式完全采用软件的方式对外设接口进行控制,所以它的硬件操作只是普通的端口读写,并无特别之处,其速度指标由总线传输速度、端口的响应速度共同决定。

    对于这种外设控制方式,速度指标关键在于软件。

    中断处理方式:

    中断处理方式本身所作的原子操作解释和程序控制方式是一致的。

    只不过因为加入了中断请求和响应机制,对状态端口的读取变成了在中断响应过程中对中断号的读取,对状态端口的判断变成了对中断入口地址的确定。

    从本质上来说,中断处理方式和程序控制方式本身的速度指标一致,没有大的差别。

    可靠性

    程序控制方式:

    由于硬件不支持中断方式,因此操作系统把CPU控制权交给应用程序后,只要应用程序不交还CPU控制权,操作系统就始终不能恢复对CPU的控制(无定时中断)。应用程序与操作系统都是软件模块,操作系统属于核心模块,它们之间存在交接CPU控制权的关系。正是由于这样的关系,一旦使用对外设的程序控制方式时,应用程序出现死锁,则操作系统永远无法恢复对系统的控制。应用程序的故障通过外设控制方式波及到作为核心模块的操作系统,因此,根据关联可靠性指标的计算可知,程序控制方式的关联可靠性指标很低。

    中断处理方式:

    由于提供定时中断,操作系统可以在应用程序当前时间片结束后通过中断服务程序重新获得对CPU的控制权。应用程序的故障不会波及到操作系统,因此,中断处理方式的关联可靠性指标高。

    可扩展性

    程序控制方式:

    由于所有应用程序中都包含对端口的操作,一旦硬件接口的设计发生变化,则所有应用程序都必须进行修改,这会使修改费用升高很多倍。因此,程序控制方式会使相关硬件模块的局部修改指标相对较低。

    中断处理方式:

    应用程序不直接操作端口,对端口的操作是由中断服务程序来完成的。如果某个硬件接口的设计发生了变化,只需要修改它相关的中断服务程序即可。因此,中断处理方式使得相关硬件模块的局部修改指标较高。

    生命期

    程序控制方式CPU查询方式)在早期的计算机系统中能够满足应用需求;但是随着外部设备种类的增多、速度差异的加大,这种方式逐渐成为系统性能提高的障碍。它的生命期只限于早期计算机阶段,因为当时外部设备少,且都是低速设备,到8位机出现以后,这种外设控制方式(体系结构)被淘汰。

    中断处理方式(外设请求方式)能够协调CPU与外设间的速度差异,能够协调各种外设间的速度差异,提高系统的工作效率(速度指标)。使应用程序与外设操作基本脱离开来,降低了程序的设备相关性(关联可靠性指标、局部修改指标)。虽然目前某些快速设备相互间的通信没有通过CPU,也没有使用中断处理方式,但是对于慢速设备、设备故障的处理来说,中断处理方式仍然是最有效的。无论将来计算机系统中的元件怎样变化,只要存在慢速设备与快速CPU之间的矛盾,使用中断处理方式都是适合的。即便不使用中断服务程序,中断的概念也会保持很久。在短时期内,计算机系统还无法在所有领域离开人工交互操作,人的操作速度一定比机器的处理速度慢,因此慢速设备将仍然保持存在(但这不是慢速设备存在的唯一原因)。正因为存在这样的需求,中断处理方式具有较长的生命期。

     (转载自:http://www.cnblogs.com/jhxk/articles/1893314.html)


    (最近笔试面试过程中,遇到了很多关于操作系统的问题(CPU多用户抢占机制,何为软中断等),作为一名计算机科学与技术专业的学生,我也曾学习过微机原理、操作系统,可我却一度认为我是做Web的,我不要学这些计算机底层的知识,现在想想这想法有多么可笑与狭隘!计算机是一个体系,要学好怎能不深入到底层,许多问题深入到底层就会豁然开朗!现在我想重拾这些,打牢基础,绝不做空中楼阁!坚持!加油!)

    展开全文
  • 启动定时任务 课程介绍看这里:https://www.cnblogs.com/zhangran/p/11963616.html 项目github地址:https://github.com/hellozhangran/happy-egg-server 爬虫 目前 node.js 爬虫工具比较火的有 node-crawler ...
  • 【前沿器】全新栏目,本栏目主要和大家一起讨论近期自己学习的心得和体会,与大家一起成长。具体介绍:仓颉专项:飞机大炮我都会,利器心法我还有。往期回顾心法利器[8] | 模型热更新小记心法利器[9] | 算法项目从...
  • 目前定时任务调度系统quartz比较出名,quartz也有集群方案,但把所有任务集中一起就构成了分布式任务系统,耦合性比较高,而且比较重。 我利用zookeeper的特性,设计了一个轻量级的定时任务调度系统。 总体的架构...
  • APScheduler最近想写个任务调度程序,于是研究了下 Python 中的任务调度工具,比较有名的是:Celery,RQ,APScheduler。Celery:非常强大的分布式任务调度框架RQ:基于Redis的作业队列工具APScheduler:一款强大的...
  • 今天带来一款安卓中比较实用的注解框架 ,其用法简单,里面编写了Android的开发中常用的一套注解,如日志记录,逐步处理,缓存,SP,延迟操作,定时任务试机制,try-catch安全机制,过滤重复单击等,随后将有更...
  • SolveFlashingAndRedraw框架是MFC解决窗口保存及绘闪烁问题的一种比较好的方案(Win32解决方法类似)。 版本历史: v1.0.1 20091126 第一版本 v1.0.2 20091212 第二版本 1. 修改了部分变量的名字使其更符合其...
  • 今天带来一款Android中比较实用的注解框架AopArms,其用法简单,里面编写了Android开发中常用的一套注解,如日志、异步处理、缓存、SP、延迟操作、定时任务试机制、try-catch安全机制、过滤频繁点击等,后续还会...
  • spring boot 定时任务

    2019-10-07 19:52:11
    定时任务实现方式 三种: ...2) 开源的第三方框架: Quartz 或者 elastic-job , 但是这个比较复杂和重量级,适用于分布式场景下的定时任务,可以根据需要多实例部署定时任务。 3) 使用Spri...
  • 失败试策略

    千次阅读 2017-09-26 19:41:46
    简介自己封装的失败试策略,比较适合访问网络或者蓝牙通信的时候任务失败试,当失败次数达到预定的次数之后,就会提示本次任务失败。 以下是代码的结构: RetryPolicyI是失败试接口; AbstractRetryPolicy...
  • SpringBoot @Scheduled 定时任务 Java实现定时任务的几种方式 基于java.util.Timer定时器,实现类似于闹钟的定时任务; 使用Quartz等开源第三方框架,重量级,使用比较复杂,适合分布式项目应用; 使用Spring提供的...
  • 请求试,异常

    2019-11-07 15:24:22
    需求:夜间定时任务比较多,偶尔遇到请求超时的情况,也可能是网络波动,总之需要做请求失败试。 1,引入spring-retry注解 <dependency> <groupId>org.springframework.retry</groupId> <...
  • 2) 开源的第三方框架: Quartz 或者 elastic-job , 但是这个比较复杂和重量级,适用于分布式场景下的定时任务,可以根据需要多实例部署定时任务。 3) 使用Spring提供的注解: @Schedule 。 如果定时任务执行...
  • SpringBoot 使用@Scheduled注解配置定时任务

    万次阅读 多人点赞 2018-01-18 16:12:31
    定时任务实现方式 ...2) 开源的第三方框架: Quartz 或者 elastic-job , 但是这个比较复杂和重量级,适用于分布式场景下的定时任务,可以根据需要多实例部署定时任务。 3) 使用Spring提供的注解: ...
  • 之前我在文章中介绍过.net中的任务调度框架Hangfire,HangFire虽然本身输入比较简单好用的,但是,如果我们的程序本身提供的服务不是任务调度,而任务调度只是里面并不重要的小功能的时候,用HangFire显得有点过了...
  • 任务扫描的架构设计

    千次阅读 2017-07-15 16:57:42
    λ 任务处理失败了,希望后续能试此任务。 λ 任务不是立即执行,而是需要在未来的某个时刻执行。 λ 任务是耗时任务,实时执行失败可能性比较大,而且会影响其他业务的进行,所以线持久化下来,后续慢慢执行。 λ...
  • 管理技巧--分派任务

    2014-02-20 18:31:44
    背景:团队中有一个员工工作任务比较轻松,而且该员工不愿意接受更多的任务,在硬性的任务指派过程中,一定会产生冲突以及影响。而对于自己的工作负荷比较重,想要想办法将自己手中的任务委托一部分出去,于是请求...
  • 版权声明: ...如果转载,请注明出处,在未经作者同意... 上次写过一篇关于贝叶斯概率论的数学,最近时间比较紧,coding的任务比较重,不过还是抽空看了一些机器学习的书和视频,其中很推荐两个:一个是stanford的mach
  • hive on tez,在执行任务的时候报错,这种情况原因是container资源被抢占或者是资源不足。...当集群上的任务比较多时,比较容易出现这个问题。 解决方案: 命令行修改默认值 set tez.am.task.max.failed....
  •  本来是要写end活动的,感觉比较简单,就直接进入task活动。  Task活动是一个难点。  定义:在jbpm中,task活动一般用来处理涉及人机交互的活动。我们可以使用task活动的assignee属性将一个任务分配给指定的...
  • Springboot2(19)定时任务

    万次阅读 2018-12-23 00:30:13
    2) 开源的第三方框架: Quartz 或者 elastic-job , 但是这个比较复杂和重量级,适用于分布式场景下的定时任务,可以根据需要多实例部署定时任务。 3) 使用Spring提供的注解: @Schedule 。 如果定时任务执行...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,444
精华内容 577
关键字:

任务比较重