在多个chrome.storage API调用中防止竞争条件的最佳方法是什么? [英] Best way to prevent race condition in multiple chrome.storage API calls?

查看:137
本文介绍了在多个chrome.storage API调用中防止竞争条件的最佳方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述





  • 其他内容将任务列表从存储中取出,并检查是否存在任务。
  • 如果有任务将其删除,则将较小的任务列表重新存储。 步骤2如果发生多个请求,则可能会出现一个竞争条件,并且相同的任务将被提供两次。



    正确的解决方案是锁定任务表,而单个任务是签出,以防止任何其他请求?

    什么是解决方案与性能影响最小,如延迟如何使用chrome.storage API实现javascript?



    一些代码例如:

      function decision_response(){
    if(script.replay_type ==reissue){
    function next_task(tasks){
    var no_tasks =( tasks.length == 0);
    if(no_tasks){
    target_complete_responses.close_requester();
    }
    else {
    var next_task = tasks.pop();
    函数notify_execute(){
    target_complete_responses.notify_requester_execute(next_task);
    }
    setTable(tasks,tasks,notify_execute);
    }
    }
    getTable(tasks,next_tasks);
    ...
    }
    ...
    }


    解决方案

    我认为,即使使用异步chrome.storage API,您也可以利用javascript在上下文中单线程的优势,从而无需锁定即可进行管理。只要你没有使用chrome.storage.sync,那就是 - 如果可能或者不可能从云端进行改变,我认为所有的投注都是关闭的。



    我会做这样的事情(注销袖口,未经测试,没有错误处理):

      var getTask =(function( ){
    //请求的私有列表
    var callbackQueue = [];

    //当chrome.storage.local.set()有$ b时调用此函数$ b //完成存储更新后的任务列表
    var tasksWritten = function(nComplete){
    //从队列中移除已完成的请求
    callbackQueue = callbackQueue.slice(nComplete);

    //处理所有新到达的请求。
    if(callbackQueue.length)
    chrome.storage.local.get('tasks',distributeTasks);
    };

    //这个函数通过chrome.storage.local.get()和
    任务列表调用
    var distributeTasks = function(items){
    //用任务调用回调s。
    var tasks = items ['tasks'];
    for(var i = 0; i< callbackQueue.length; ++ i)
    callbackQueue [i](tasks [i] || null);

    //更新并存储任务列表。将请求的数量
    //作为参数传递给set()处理程序,因为队列
    //长度可能会在调用处理程序时发生更改。
    chrome.storage.local.set(
    {'tasks':tasks.slice(callbackQueue.length)},
    function(){
    tasksWritten(callbackQueue.length);
    }
    );
    };

    //这是消费者调用获取新的
    //任务的公共函数任务。该任务通过回调参数返回。
    return function(callback){
    if(callbackQueue.push(callback)=== 1)
    chrome.storage.local.get('tasks',distributeTasks);
    };
    })();

    这将消费者的任务请求存储为本地内存队列中的回调。当新的请求到达时,回调被添加到队列中,任务列表被取出 iff 这是队列中唯一的请求。否则,我们可以假设这个队列已经被处理了(这是一个隐含的锁,它只允许一个执行链访问任务列表)。

    当任务列表被提取,任务被分配到请求。请注意,如果在获取完成之前已经有更多人到达,则可能会有多个请求。如果有更多请求比任务更多,此代码只会将null传递给回调函数。要在更多任务到达之前阻止请求,请保留未使用的回调,并在添加任务时重新启动请求处理。如果任务可以动态生成以及消耗,请记住,竞争条件也需要在那里防止,但不会在这里显示。



    重要的是防止读取任务列表,直到更新的任务列表被存储。要完成此操作,请求将不会从队列中删除,直到更新完成。然后,我们需要确保处理同时到达的任何请求(可以将对chrome.storage.local.get()的调用短路,但为简单起见,我是这样做的)。



    这种方法应该非常有效,因为它应尽可能减少对任务列表的更新,同时尽可能快地响应。没有明确的锁定或等待。如果在其他上下文中有任务使用者,则设置一个调用getTask()函数的chrome.extension消息处理程序。


    1. Something requests a task
    2. Something else pulls the task list out of storage, and checks if there are tasks there.
    3. If there are tasks it removes one and the smaller "task list" is put back in storage.

    Between steps 2 and 3 a race condition can occur if multiple requests occur, and the same task will be served twice.

    Is the correct resolution to "lock" the "tasks table" while a single task is "checked out", to prevent any other requests?

    What is the solution with the least performance impact, such as delay of execution, and how should it be implemented in javascript with chrome.storage API ?

    Some code for example :

    function decide_response ( ) {
        if(script.replay_type == "reissue") {
                function next_task( tasks ) {
                    var no_tasks = (tasks.length == 0);
                    if( no_tasks ) {
                        target_complete_responses.close_requester();
                    }
                    else {
                        var next_task = tasks.pop();
                        function notify_execute () {
                            target_complete_responses.notify_requester_execute( next_task );
                        }
                        setTable("tasks", tasks, notify_execute);
                    }
                }
                getTable( "tasks", next_tasks );
        ...
        }
    ...
    }
    

    解决方案

    I think you can manage without a lock by taking advantage of the fact that javascript is single-threaded within a context, even with the asynchronous chrome.storage API. As long as you're not using chrome.storage.sync, that is - if there may or may not be changes from the cloud I think all bets are off.

    I would do something like this (written off the cuff, not tested, no error handling):

    var getTask = (function() {
      // Private list of requests.
      var callbackQueue = [];
    
      // This function is called when chrome.storage.local.set() has
      // completed storing the updated task list.
      var tasksWritten = function(nComplete) {
        // Remove completed requests from the queue.
        callbackQueue = callbackQueue.slice(nComplete);
    
        // Handle any newly arrived requests.
        if (callbackQueue.length)
          chrome.storage.local.get('tasks', distributeTasks);
      };
    
      // This function is called via chrome.storage.local.get() with the
      // task list.
      var distributeTasks = function(items) {
        // Invoke callbacks with tasks.
        var tasks = items['tasks'];
        for (var i = 0; i < callbackQueue.length; ++i)
          callbackQueue[i](tasks[i] || null);
    
        // Update and store the task list. Pass the number of requests
        // handled as an argument to the set() handler because the queue
        // length may change by the time the handler is invoked.
        chrome.storage.local.set(
          { 'tasks': tasks.slice(callbackQueue.length) },
          function() {
            tasksWritten(callbackQueue.length);
          }
        );
      };
    
      // This is the public function task consumers call to get a new
      // task. The task is returned via the callback argument.
      return function(callback) {
        if (callbackQueue.push(callback) === 1)
          chrome.storage.local.get('tasks', distributeTasks);
      };
    })();
    

    This stores task requests from consumers as callbacks in a queue in local memory. When a new request arrives, the callback is added to the queue and the task list is fetched iff this is the only request in the queue. Otherwise we can assume that the queue is already being processed (this is an implicit lock that allows only one strand of execution to access the task list).

    When the task list is fetched, tasks are distributed to requests. Note that there may be more than one request if more have arrived before the fetch completed. This code just passes null to a callback if there are more requests than tasks. To instead block requests until more tasks arrive, hold unused callbacks and restart request processing when tasks are added. If tasks can be dynamically produced as well as consumed, remember that race conditions will need to be prevented there as well but is not shown here.

    It's important to prevent reading the task list again until the updated task list is stored. To accomplish this, requests aren't removed from the queue until the update is complete. Then we need to make sure to process any requests that arrived in the meantime (it's possible to short-circuit the call to chrome.storage.local.get() but I did it this way for simplicity).

    This approach should be pretty efficient in the sense that it should minimize updates to the task list while still responding as quickly as possible. There is no explicit locking or waiting. If you have task consumers in other contexts, set up a chrome.extension message handler that calls the getTask() function.

    这篇关于在多个chrome.storage API调用中防止竞争条件的最佳方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆