代码之家  ›  专栏  ›  技术社区  ›  Viktoria

接收数据导致“打开的文件太多”

  •  1
  • Viktoria  · 技术社区  · 7 年前

    在我的客户机中,我通过ZeroMQ接收大量输入,这些输入需要不断更新。我的服务器是用python编写的,但这并不重要。这就是我在 MainActivity :

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            /********************************NETWORK********************************/
            new NetworkCall().execute("");
        }
    
        private class NetworkCall extends AsyncTask<String, Void, String> {
    
            @Override
            protected String doInBackground(String... params) {
                while (true) {
                    try {
                        ZMQ.Context context = ZMQ.context(1);
    
                        // Connect to server
                        ZMQ.Socket requester = context.socket(ZMQ.REQ);
                        String address = "tcp://xxx.xx.xx.xx";
                        int port = 5000;
                        requester.connect(address + ":" + port);
    
                        // Initialize poll set
                        ZMQ.Poller poller = new ZMQ.Poller(1);
                        poller.register(requester, ZMQ.Poller.POLLIN);
    
                        requester.send("COORDINATES");
    
                        //while (true) {
                        String data;
                        poller.poll();
    
                        data = requester.recvStr();
                        System.out.println(data);
    
                        if (data == null) {
                            try {
                                sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        } requester.close();
                    } catch (IllegalStateException ise) {
                        ise.printStackTrace();
                    }
                }
            }
    
            @Override
            protected void onPostExecute(String result) {
            }
    
            @Override
            protected void onPreExecute() {
            }
    
            @Override
            protected void onProgressUpdate(Void... values) {
            }
        }
    }
    

    在我的设备上执行此代码后,我将从服务器接收到大约5-9个输入数据字符串,但随后会出现以下异常:

    E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #2
                      Process: com.example.viktoria.gazefocus, PID: 31339
                      java.lang.RuntimeException: An error occurred while executing doInBackground()
                          at android.os.AsyncTask$3.done(AsyncTask.java:353)
                          at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
                          at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
                          at java.util.concurrent.FutureTask.run(FutureTask.java:271)
                          at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
                          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
                          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
                          at java.lang.Thread.run(Thread.java:764)
                       Caused by: com.example.viktoria.gazefocus.zmq.ZError$IOException: java.io.IOException: Too many open files
                          at com.example.viktoria.gazefocus.zmq.Signaler.makeFdPair(Signaler.java:94)
                          at com.example.viktoria.gazefocus.zmq.Signaler.<init>(Signaler.java:50)
                          at com.example.viktoria.gazefocus.zmq.Mailbox.<init>(Mailbox.java:51)
                          at com.example.viktoria.gazefocus.zmq.Ctx.<init>(Ctx.java:128)
                          at com.example.viktoria.gazefocus.zmq.ZMQ.zmq_ctx_new(ZMQ.java:244)
                          at com.example.viktoria.gazefocus.zmq.ZMQ.zmqInit(ZMQ.java:277)
                          at org.zeromq.ZMQ$Context.<init>(ZMQ.java:269)
                          at org.zeromq.ZMQ.context(ZMQ.java:254)
                          at com.example.viktoria.gazefocus.MainActivity$NetworkCall.doInBackground(MainActivity.java:73)
                          at com.example.viktoria.gazefocus.MainActivity$NetworkCall.doInBackground(MainActivity.java:67)
                          at android.os.AsyncTask$2.call(AsyncTask.java:333)
                          at java.util.concurrent.FutureTask.run(FutureTask.java:266)
                          at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245) 
                          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
                          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
                          at java.lang.Thread.run(Thread.java:764) 
                       Caused by: java.io.IOException: Too many open files
                          at sun.nio.ch.IOUtil.makePipe(Native Method)
                          at sun.nio.ch.PipeImpl.<init>(PipeImpl.java:42)
                          at sun.nio.ch.SelectorProviderImpl.openPipe(SelectorProviderImpl.java:50)
                          at java.nio.channels.Pipe.open(Pipe.java:155)
                          at com.example.viktoria.gazefocus.zmq.Signaler.makeFdPair(Signaler.java:91)
                          at com.example.viktoria.gazefocus.zmq.Signaler.<init>(Signaler.java:50) 
                          at com.example.viktoria.gazefocus.zmq.Mailbox.<init>(Mailbox.java:51) 
                          at com.example.viktoria.gazefocus.zmq.Ctx.<init>(Ctx.java:128) 
                          at com.example.viktoria.gazefocus.zmq.ZMQ.zmq_ctx_new(ZMQ.java:244) 
                          at com.example.viktoria.gazefocus.zmq.ZMQ.zmqInit(ZMQ.java:277) 
                          at org.zeromq.ZMQ$Context.<init>(ZMQ.java:269) 
                          at org.zeromq.ZMQ.context(ZMQ.java:254) 
                          at com.example.viktoria.gazefocus.MainActivity$NetworkCall.doInBackground(MainActivity.java:73) 
                          at com.example.viktoria.gazefocus.MainActivity$NetworkCall.doInBackground(MainActivity.java:67) 
                          at android.os.AsyncTask$2.call(AsyncTask.java:333) 
                          at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
                          at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245) 
                          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
                          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
                          at java.lang.Thread.run(Thread.java:764) 
    

    显然打开的文件太多了。经过研究(我使用的是Ubuntu 16.04),我改变了 ulimit 具有 ulimit -n 10000 。但这种例外情况仍会发生。有时我得到更多的输入数据,有时更少。如果我设置 Executor executor = Executors.newFixedThreadPool(5); 进入 onCreate() 方法,什么都不会改变。

    如何克服这个问题?

    感谢阅读!

    2 回复  |  直到 7 年前
        1
  •  1
  •   user3666197    7 年前

    你有漏洞,因为你没有关闭/结束/释放某些东西。我 认为 必须终止上下文: context.term() 关闭请求者后。。。

        2
  •  0
  •   user3666197    7 年前

    嗯,在 在设计上,信令/消息传递的基础设施设置成本不容忽视。有些用例更具预见性,有些则更少。

    总是得到一个新的 Context() 每个方法调用的 .term() * -这种方法肯定比挂起的应用程序或冻结的设备要好,但它远远不是一个公平的设计,它考虑了进程延迟和资源的“生态”。

    更好地首先建立一个资源的半持久性基础架构(每个 上下文() -实例通常是一个非常昂贵的实例(API 4.2+截至2018-Q1),对于 Socket() -实例,但类似于 Poller() 以及所有的内部访问点注册挂钩,但该原则也可能扩展到这些挂钩上)。

    早期对代码进行重新分解将有助于避免将昂贵的资源作为“可消耗的一次性资源”使用而扩展情况。

    本节:

          while (true) {
                 try {
                        ZMQ.Context context = ZMQ.context(1);
    
                        //                     Connect to server
                        ZMQ.Socket requester = context.socket( ZMQ.REQ );
                        String address = "tcp://xxx.xx.xx.xx";
                        int port = 5000;
                        requester.connect( address + ":" + port );
                        ...
                 }
                 ...
          }
    

    正是一种破坏资源的反模式,加上重复的延迟,甚至有远程挂断、远程拒绝和类似问题的风险。