# Buggy code
def tile(cls, op: "LGBMTrain"):
    ctx = get_context()
    if ctx.running_mode != RunningMode.distributed:
        assert all(len(inp.chunks) == 1 for inp in op.inputs)

        chunk_op = op.copy().reset_key()
        out_chunk = chunk_op.new_chunk(
            [inp.chunks[0] for inp in op.inputs], shape=(1,), index=(0,)
        )
        new_op = op.copy()
        return new_op.new_tileables(op.inputs, chunks=[out_chunk], nsplits=((1,),))
    else:
        data = op.data
        worker_to_args = defaultdict(dict)

        workers = cls._get_data_chunks_workers(ctx, data)
        worker_to_endpoint = cls._build_lgbm_endpoints(workers, op.lgbm_port)
        worker_endpoints = list(worker_to_endpoint.values())

        for arg in ["_data", "_label", "_sample_weight", "_init_score"]:
            if getattr(op, arg) is not None:
                for worker, chunk in cls._concat_chunks_by_worker(
                    getattr(op, arg).chunks, workers
                ).items():
                    worker_to_args[worker][arg] = chunk

        if op.eval_datas:
            eval_workers_list = [
                cls._get_data_chunks_workers(ctx, d) for d in op.eval_datas
            ]
            extra_workers = reduce(
                operator.or_, (set(w) for w in eval_workers_list)
            ) - set(workers)
            worker_remap = dict(zip(extra_workers, itertools.cycle(workers)))
            if worker_remap:
                eval_workers_list = [
                    [worker_remap.get(w, w) for w in wl] for wl in eval_workers_list
                ]

            for arg in [
                "_eval_datas",
                "_eval_labels",
                "_eval_sample_weights",
                "_eval_init_scores",
            ]:
                if getattr(op, arg):
                    for tileable, eval_workers in zip(
                        getattr(op, arg), eval_workers_list
                    ):
                        for worker, chunk in cls._concat_chunks_by_worker(
                            tileable.chunks, eval_workers
                        ).items():
                            if arg not in worker_to_args[worker]:
                                worker_to_args[worker][arg] = []
                            worker_to_args[worker][arg].append(chunk)

        out_chunks = []
        for worker in workers:
            chunk_op = op.copy().reset_key()

            chunk_op._expect_worker = worker
            chunk_op._lgbm_endpoints = worker_endpoints
            chunk_op._lgbm_port = int(worker_to_endpoint[worker].rsplit(":", 1)[-1])

            input_chunks = []
            concat_args = worker_to_args.get(worker, {})
            for arg in [
                "_data",
                "_label",
                "_sample_weight",
                "_init_score",
                "_eval_datas",
                "_eval_labels",
                "_eval_sample_weights",
                "_eval_init_scores",
            ]:
                arg_val = getattr(op, arg)
                if arg_val:
                    arg_chunk = concat_args.get(arg)
                    setattr(chunk_op, arg, arg_chunk)
                    if isinstance(arg_chunk, list):
                        input_chunks.extend(arg_chunk)
                    else:
                        input_chunks.append(arg_chunk)

            data_chunk = concat_args["_data"]
            out_chunk = chunk_op.new_chunk(
                input_chunks, shape=(np.nan,), index=data_chunk.index[:1]
            )
            out_chunks.append(out_chunk)

        new_op = op.copy()
        return new_op.new_tileables(
            op.inputs, chunks=out_chunks, nsplits=((np.nan for _ in out_chunks),)
        )


# Traceback (lightgbm.basic.LightGBMError)
Traceback (most recent call last):
File "/home/admin/work/_public-mars-0.6.2.zip/mars/promise.py", line 100, in _wrapped
result = func(*args, **kwargs)
File "/home/admin/work/_public-mars-0.6.2.zip/mars/worker/calc.py", line 301, in <lambda>
.then(lambda context_dict: _start_calc(context_dict)) \
File "/home/admin/work/_public-mars-0.6.2.zip/mars/worker/calc.py", line 276, in _start_calc
return self._calc_results(session_id, graph_key, graph, context_dict, chunk_targets)
File "/home/admin/work/_public-mars-0.6.2.zip/mars/utils.py", line 377, in _wrapped
return func(*args, **kwargs)
File "/home/admin/work/_public-mars-0.6.2.zip/mars/worker/calc.py", line 200, in _calc_results
chunk_targets, retval=False).result()
File "src/gevent/event.py", line 383, in gevent._gevent_cevent.AsyncResult.result
File "src/gevent/event.py", line 305, in gevent._gevent_cevent.AsyncResult.get
File "src/gevent/event.py", line 335, in gevent._gevent_cevent.AsyncResult.get
File "src/gevent/event.py", line 323, in gevent._gevent_cevent.AsyncResult.get
File "src/gevent/event.py", line 303, in gevent._gevent_cevent.AsyncResult._raise_exception
File "/opt/conda/lib/python3.7/site-packages/gevent/_compat.py", line 65, in reraise
raise value.with_traceback(tb)
File "/opt/conda/lib/python3.7/site-packages/gevent/threadpool.py", line 142, in __run_task
thread_result.set(func(*args, **kwargs))
File "mars/actors/pool/gevent_pool.pyx", line 127, in mars.actors.pool.gevent_pool.GeventThreadPool._wrap_watch.inner
result = fn(*args, **kwargs)
File "/home/admin/work/_public-mars-0.6.2.zip/mars/executor.py", line 698, in execute_graph
res = graph_execution.execute(retval)
File "/home/admin/work/_public-mars-0.6.2.zip/mars/executor.py", line 579, in execute
future.result()
File "/opt/conda/lib/python3.7/concurrent/futures/_base.py", line 435, in result
return self.__get_result()
File "/opt/conda/lib/python3.7/concurrent/futures/_base.py", line 384, in __get_result
raise self._exception
File "/opt/conda/lib/python3.7/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "/home/admin/work/_public-mars-0.6.2.zip/mars/utils.py", line 451, in _inner
return func(*args, **kwargs)
File "/home/admin/work/_public-mars-0.6.2.zip/mars/executor.py", line 446, in _execute_operand
self.handle_op(first_op, results, self._mock)
File "/home/admin/work/_public-mars-0.6.2.zip/mars/executor.py", line 378, in handle_op
return Executor.handle(*args, **kw)
File "/home/admin/work/_public-mars-0.6.2.zip/mars/executor.py", line 649, in handle
return runner(results, op)
File "/home/admin/work/_public-mars-0.6.2.zip/mars/learn/contrib/lightgbm/_train.py", line 304, in execute
eval_init_score=eval_init_score, **op.kwds)
File "/opt/conda/lib/python3.7/site-packages/lightgbm/sklearn.py", line 800, in fit
callbacks=callbacks)
File "/opt/conda/lib/python3.7/site-packages/lightgbm/sklearn.py", line 595, in fit
callbacks=callbacks)
File "/opt/conda/lib/python3.7/site-packages/lightgbm/engine.py", line 228, in train
booster = Booster(params=params, train_set=train_set)
File "/opt/conda/lib/python3.7/site-packages/lightgbm/basic.py", line 1659, in __init__
num_machines=params.get("num_machines", num_machines))
File "/opt/conda/lib/python3.7/site-packages/lightgbm/basic.py", line 1790, in set_network
ctypes.c_int(num_machines)))
File "/opt/conda/lib/python3.7/site-packages/lightgbm/basic.py", line 47, in _safe_call
raise LightGBMError(decode_string(_LIB.LGBM_GetLastError()))
lightgbm.basic.LightGBMError: Binding port 43458 failed

# Fixed code
def tile(cls, op: "LGBMTrain"):
    ctx = get_context()
    if ctx.running_mode != RunningMode.distributed:
        assert all(len(inp.chunks) == 1 for inp in op.inputs)

        chunk_op = op.copy().reset_key()
        out_chunk = chunk_op.new_chunk(
            [inp.chunks[0] for inp in op.inputs], shape=(1,), index=(0,)
        )
        new_op = op.copy()
        return new_op.new_tileables(op.inputs, chunks=[out_chunk], nsplits=((1,),))
    else:
        data = op.data
        worker_to_args = defaultdict(dict)

        workers = cls._get_data_chunks_workers(ctx, data)

        for arg in ["_data", "_label", "_sample_weight", "_init_score"]:
            if getattr(op, arg) is not None:
                for worker, chunk in cls._concat_chunks_by_worker(
                    getattr(op, arg).chunks, workers
                ).items():
                    worker_to_args[worker][arg] = chunk

        if op.eval_datas:
            eval_workers_list = [
                cls._get_data_chunks_workers(ctx, d) for d in op.eval_datas
            ]
            extra_workers = reduce(
                operator.or_, (set(w) for w in eval_workers_list)
            ) - set(workers)
            worker_remap = dict(zip(extra_workers, itertools.cycle(workers)))
            if worker_remap:
                eval_workers_list = [
                    [worker_remap.get(w, w) for w in wl] for wl in eval_workers_list
                ]

            for arg in [
                "_eval_datas",
                "_eval_labels",
                "_eval_sample_weights",
                "_eval_init_scores",
            ]:
                if getattr(op, arg):
                    for tileable, eval_workers in zip(
                        getattr(op, arg), eval_workers_list
                    ):
                        for worker, chunk in cls._concat_chunks_by_worker(
                            tileable.chunks, eval_workers
                        ).items():
                            if arg not in worker_to_args[worker]:
                                worker_to_args[worker][arg] = []
                            worker_to_args[worker][arg].append(chunk)

        out_chunks = []
        workers = list(set(workers))
        for worker_id, worker in enumerate(workers):
            chunk_op = op.copy().reset_key()
            chunk_op._expect_worker = worker

            input_chunks = []
            concat_args = worker_to_args.get(worker, {})
            for arg in [
                "_data",
                "_label",
                "_sample_weight",
                "_init_score",
                "_eval_datas",
                "_eval_labels",
                "_eval_sample_weights",
                "_eval_init_scores",
            ]:
                arg_val = getattr(op, arg)
                if arg_val:
                    arg_chunk = concat_args.get(arg)
                    setattr(chunk_op, arg, arg_chunk)
                    if isinstance(arg_chunk, list):
                        input_chunks.extend(arg_chunk)
                    else:
                        input_chunks.append(arg_chunk)

            worker_ports_chunk = (
                collect_ports(workers, op.data)._inplace_tile().chunks[0]
            )
            input_chunks.append(worker_ports_chunk)

            chunk_op._workers = workers
            chunk_op._worker_ports = worker_ports_chunk
            chunk_op._worker_id = worker_id

            data_chunk = concat_args["_data"]
            out_chunk = chunk_op.new_chunk(
                input_chunks, shape=(np.nan,), index=data_chunk.index[:1]
            )
            out_chunks.append(out_chunk)

        new_op = op.copy()
        return new_op.new_tileables(
            op.inputs, chunks=out_chunks, nsplits=((np.nan for _ in out_chunks),)
        )